最佳性能查询"选择组中的最大值"?

时间: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;