优化嵌套查询到单个查询

时间:2012-01-05 09:39:31

标签: mysql sql

我有一个(MySQL)表,其中包含上次扫描主机的日期以及报告ID:

+--------------+---------------------+--------+
| 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 |
+--------------+---------------------+--------+

我想选择所有主机的列表,其中包含上次扫描的日期和相应的报告ID。我已经构建了以下嵌套查询,但我确信它可以在一个查询中完成:

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 个答案:

答案 0 :(得分:3)

不,但您可以在查询中执行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` ) ;

否则您的查询将执行两次文件排序。

答案 1 :(得分:0)

如果您只想从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;

虽然它仍然是嵌套但它确实避免了“双重选择”问题。不确定它是否会更高效 - 有点取决于你拥有的索引和数据量。