Оптимизировать вложенный запрос для одного запроса - PullRequest
0 голосов
/ 05 января 2012

У меня есть таблица (MySQL), содержащая даты последнего сканирования хостов в сочетании с идентификатором отчета:

+--------------+---------------------+--------+
| host         | last_scan           | report |
+--------------+---------------------+--------+
| 112.86.115.0 | 2012-01-03 01:39:30 |      4 |
| 112.86.115.1 | 2012-01-03 01:39:30 |      4 |
| 112.86.115.2 | 2012-01-03 02:03:40 |      4 |
| 112.86.115.2 | 2012-01-03 04:33:47 |      5 |
| 112.86.115.1 | 2012-01-03 04:20:23 |      5 |
| 112.86.115.6 | 2012-01-03 04:20:23 |      5 |
| 112.86.115.2 | 2012-01-05 04:29:46 |      8 |
| 112.86.115.6 | 2012-01-05 04:17:35 |      8 |
| 112.86.115.5 | 2012-01-05 04:29:48 |      8 |
| 112.86.115.4 | 2012-01-05 04:17:37 |      8 |
+--------------+---------------------+--------+

Я хочу выбрать список всех хостов с датой последнего сканирования исоответствующий идентификатор отчета.Я построил следующий вложенный запрос, но я уверен, что это можно сделать за один запрос:

SELECT rh.host, rh.report, rh.last_scan
FROM report_hosts rh
WHERE rh.report = (
    SELECT rh2.report
    FROM report_hosts rh2
    WHERE rh2.host = rh.host
    ORDER BY rh2.last_scan DESC
    LIMIT 1
)
GROUP BY rh.host

Возможно ли это сделать с помощью одного не вложенного запроса?

Ответы [ 2 ]

3 голосов
/ 05 января 2012

Нет, но вы можете сделать JOIN в своем запросе

SELECT x.*
FROM report_hosts x
INNER JOIN (
    SELECT host,MAX(last_scan) AS last_scan FROM report_hosts GROUP BY host
) y ON x.host=y.host AND x.last_scan=y.last_scan

Ваш запрос выполняет сортировку файлов, что очень неэффективно.Мои решения нет.Очень желательно создать индекс для этой таблицы

ALTER TABLE `report_hosts` ADD INDEX ( `host` , `last_scan` ) ;

В противном случае ваш запрос выполнит сортировку файлов дважды.

0 голосов
/ 05 января 2012

Если вы хотите выбрать из таблицы report_hosts только один раз, вы можете использовать своего рода метод 'RANK OVER PARTITION' (доступен в Oracle, но, к сожалению, в MySQL нет). Примерно так должно работать:

select h.host,h.last_scan as most_recent_scan,h.report
from
(
select rh.*,
case when @curHost != rh.host then @rank := 1 else @rank := @rank+1 end as rank,
case when @curHost != rh.host then @curHost := rh.host end
from report_hosts rh
cross join (select @rank := null,@curHost = null) t
order by host asc,last_scan desc
) h
where h.rank = 1;

Конечно, он все еще является вложенным, но избегает проблемы двойного выбора. Не уверен, будет ли он более эффективным или нет - все зависит от того, какие у вас индексы и объем данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...