SQL性能MAX()

Ole*_*ers 12 sql t-sql sql-server performance

刚收到一个小问题.尝试获取表的单个最大值时.哪一个更好?

SELECT MAX(id) FROM myTable WHERE (whatever)
Run Code Online (Sandbox Code Playgroud)

要么

SELECT TOP 1 id FROM myTable WHERE (whatever) ORDER BY id DESC
Run Code Online (Sandbox Code Playgroud)

我正在使用Microsoft SQL Server 2012

Aar*_*and 29

因为您可以通过检查执行计划来测试自己,所以没有区别.如果id是聚簇索引,您应该看到有序的聚簇索引扫描; 如果没有编制索引,您仍然可以看到表扫描或聚簇索引扫描,但在任何一种情况下都不会对它进行排序.

TOP 1如果要从行中提取其他值,该方法可能很有用,这比在子查询中拉出最大值然后加入更容易.如果您想要该行中的其他值,则需要在两种情况下指定如何处理关系.

话虽如此,在某些情况下计划可能会有所不同,因此根据列是否已编制索引以及是否单调增加来进行测试非常重要.我创建了一个简单的表并插入了50000行:

CREATE TABLE dbo.x
(
  a INT, b INT, c INT, d INT, 
  e DATETIME, f DATETIME, g DATETIME, h DATETIME
);
CREATE UNIQUE CLUSTERED INDEX a ON dbo.x(a);
CREATE INDEX b ON dbo.x(b)
CREATE INDEX e ON dbo.x(e);
CREATE INDEX f ON dbo.x(f);

INSERT dbo.x(a, b, c, d, e, f, g, h)
SELECT 
  n.rn, -- ints monotonically increasing
  n.a,  -- ints in random order
  n.rn, 
  n.a, 
  DATEADD(DAY, n.rn/100, '20100101'), -- dates monotonically increasing
  DATEADD(DAY, -n.a % 1000, '20120101'),     -- dates in random order
  DATEADD(DAY, n.rn/100, '20100101'),
  DATEADD(DAY, -n.a % 1000, '20120101')
FROM
(
  SELECT TOP (50000) 
     (ABS(s1.[object_id]) % 10000) + 1, 
     rn = ROW_NUMBER() OVER (ORDER BY s2.[object_id])
  FROM sys.all_objects AS s1 
  CROSS JOIN sys.all_objects AS s2
) AS n(a,rn);
GO
Run Code Online (Sandbox Code Playgroud)

在我的系统上,这创建了a/c中的值,从1到50000,b/d在3到9994之间,e/g从2010-01-01到2011-05-16,以及f/h从2009-04-28到2012-01-01.

首先,让我们比较索引的单调递增整数列a和c.a有聚簇索引,c不:

SELECT MAX(a) FROM dbo.x;
SELECT TOP (1) a FROM dbo.x ORDER BY a DESC;

SELECT MAX(c) FROM dbo.x;
SELECT TOP (1) c FROM dbo.x ORDER BY c DESC;
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述

第四个问题的一个大问题是MAX,它需要排序.这是3与4相比:

在此输入图像描述

在此输入图像描述

这将是所有这些查询变体中的常见问题:MAX针对未编制索引的列将能够在群集索引扫描上捎带并执行流聚合,同时TOP 1需要执行更昂贵的排序.

我测试了并且在测试b + d,e + g和f + h之间看到了完全相同的结果.

所以,在我看来,除了生产更多的标准一致性代码,还有一个潜在的性能好处是用MAX有利于TOP 1根据底层表和索引(你已经把你的代码在生产后可以改变)上.所以我想说,没有进一步的信息,MAX更可取.

(正如我之前所说的那样TOP 1,如果你正在提取额外的列,可能真的是你所追求的行为.如果那就是你所追求的,你也会想要测试MAX+ JOIN方法.)


Luc*_*ero 5

第一个肯定是明确的意图.

对于这个特定的查询,应该没有显着的性能差异(它们实际上应该非常相同,即使在没有行的情况下结果也不同myTable).除非您有合理的理由来调整查询(例如,经过验证的性能问题),否则请始终选择显示代码意图的那个.

  • 另一个优点是第一个查询也与DBMS无关,这意味着您可以采用相同的查询并在几乎任何其他DBMS上运行它仍然可以工作,而第二个查询使用特定于SQL服务器的`TOP`仅由SQL-Server支持的关键字. (3认同)