#mysql #subquery
#mysql #подзапрос
Вопрос:
Можно ли изменить следующий запрос MySQL, чтобы использовать соединение вместо подзапроса для повышения эффективности (или другого способа повышения эффективности)? У меня есть таблица с посещениями пациентов в отделении неотложной помощи. В таблице указано время прибытия и отправления. Мне нужно, чтобы запрос возвращал общее количество пациентов, которые уже присутствовали в отделении неотложной помощи («перепись»), когда пациент прибыл.
Моя таблица выглядит примерно так:
------ ------ --------------------- ---------------------
| id | name | arrival | departure |
------ ------ --------------------- ---------------------
| 1 | Joe | 2010-01-01 00:00:00 | 2010-01-01 02:00:00 |
| 2 | John | 2010-01-01 00:05:00 | 2010-01-01 03:00:00 |
| 3 | Jane | 2010-01-01 01:00:00 | 2010-01-01 04:00:00 |
...
С желаемым результатом, подобным этому:
------ --------
| name | census |
------ --------
| Joe | 0 |
| John | 1 |
| Jane | 2 |
...
Следующий запрос работает, но довольно медленно (около 3,5 секунд на 180 000 строк). Есть ли способ повысить эффективность этого запроса (с помощью какого-либо соединения или другого метода)?
select name, arrival,
(SELECT count(*)
FROM patient_arrivals as b
WHERE b.arrival <= a.arrival and b.departure >= a.departure) as census
FROM patient_arrivals as a
Ответ №1:
Я не думаю, что a join
поможет. Вместо этого вам нужно реструктурировать запрос. Следующее получает количество пациентов в палате в любой конкретный момент времени:
select t, sum(num) as num, @total := @total num as total
from (select arrival as t, 1 as num
from patient_arrivals
union all
select departure, -1
from patient_arrivals
) t cross join
(select @total := 0) vars
group by t
order by t
Затем вы можете использовать это как подзапрос для соединения:
select pa.*, t.total as census
from patient_arrivals pa join
(select t, sum(num) as num, @total := @total num as total
from (select arrival as t, 1 as num
from patient_arrivals
union all
select departure, -1
from patient_arrivals
) t cross join
(select @total := 0) vars
group by t
order by t
) tnum
on pa.arrival = tnum.t;
Это дает номер, когда пациент прибывает. Для общего количества, которое перекрывается:
select pa.*, max(t.total) as census
from patient_arrivals pa join
(select t, sum(num) as num, @total := @total num as total
from (select arrival as t, 1 as num
from patient_arrivals
union all
select departure, -1
from patient_arrivals
) t cross join
(select @total := 0) vars
group by t
order by t
) tnum
on tnum.t between pa.arrival and pa.departure
group by pa.id