最佳性能查询"选择组中的最大值"?
时间:2020-03-06 14:23:01 来源:igfitidea点击:
我有一个简单的表注释(id INT,version INT,comment VARCHAR(140))
,其中的一些内容是这样的:
1|1|hallo1| 1|2|hallo2| 1|3|hallo3| 2|1|hallo1| 2|2|hallo2|
我正在搜索一条SQL语句,该语句将返回具有最高修订版本的每个注释:
1|3|hallo3| 2|2|hallo2|
我想出了以下解决方案:
select id, revision, comment from comments where revision = ( select max(revision) from comments as f where f.id = comments.id );
但是对于大型数据集,它的速度非常慢。是否有更好的查询来完成此任务?
解决方案
- 确保我们已正确设置索引。索引ID,修订将是很好的。
- 这是我们查询的另一种说法。尚未检查其执行计划,但是如果我们很好地设置了索引,它应该会有所帮助:
SELECT c.* FROM comments c INNER JOIN ( SELECT id,max(revision) AS maxrev FROM comments GROUP BY id ) b ON c.id=b.id AND c.revision=b.maxrev
编辑添加:
- 如果我们使用的是SQL Server,则可能还需要签出索引视图:http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx
再次编辑以添加信息:
Subquery: 25157 records 2 seconds Execution plan includes an Index Seek (82%) base and a Segment (17%) Left Outer Join: 25160 records 3 seconds Execution plan includes two Index Scans @ 22% each with a Right Outer Merge at 45% and a Filter at 11%
我仍然会使用子查询。
这是一种使用适当的索引不会令人费解的速度并且不使用子选择的方法:
SELECT comments.ID, comments.revision, comments.comment FROM comments LEFT OUTER JOIN comments AS maxcomments ON maxcomments.ID= comments.ID AND maxcomments.revision > comments.revision WHERE maxcomments.revision IS NULL
从此处的查询改编而成:
http://www.xaprb.com/blog/2007/03/14/how-to-find-the-max-row-per-group-in-sql-without-subqueries/
(从谷歌搜索:通过SQL最大组)
使用我们的其中一个表进行了测试,该表总共有近一百万行。在两个字段FIELD2和FIELD3上都存在索引。在不到3秒的时间内,查询在我们的开发箱中返回了83953行。
select FIELD1, FIELD2, FIELD3 from OURTABLE (nolock) T1 WHERE FIELD3 = ( SELECT MAX(FIELD3) FROM OURTABLE T2 (nolock) WHERE T1.FIELD2=T2.FIELD2 ) ORDER BY FIELD2 DESC
从左字段开始的想法,但是如何在表中添加一个额外的字段:
CurrentRevision bit not null
然后,当我们进行更改时,在新修订版上设置标志,并在所有以前的修订版上将其删除。
查询将变成:
select Id, Comment from Comments where CurrentRevision = 1
这在数据库上会容易得多,因此也要快得多。
一种非常干净的方式来执行"最新的按ID排序x"类型查询。正确索引也应该很容易。
SELECT id, revision, comment FROM comments WHERE (id, revision) IN ( SELECT id, MAX(revision) FROM comments -- WHERE clause comes here if needed GROUP BY id )
对于大型表,我发现此解决方案可以具有更好的性能:
SELECT c1.id, c1.revision, c1.comment FROM comments c1 INNER JOIN ( SELECT id, max(revision) AS max_revision FROM comments GROUP BY id ) c2 ON c1.id = c2.id AND c1.revision = c2.max_revision
分析将是我的建议。
select id, max_revision, comment from (select c.id, c.comment, c.revision, max(c.revision)over(partition by c.id) as max_revision from comments c) where revision = max_revision;