SQL 性能 MAX()

标签 sql sql-server performance max query-optimization

我有一个小问题。当尝试获取表的单个最大值时。哪个更好?

SELECT MAX(id) FROM myTable WHERE (whatever)

SELECT TOP 1 id FROM myTable WHERE (whatever) ORDER BY id DESC

我使用的是 Microsoft SQL Server 2012

最佳答案

不会有什么区别,因为您可以通过检查执行计划来测试自己。如果 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

在我的系统上,这创建了 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;

结果:

enter image description here

第四个查询的大问题是,与 MAX 不同,它需要排序。这是 3 与 4 的比较:

enter image description here

enter image description here

这将是所有这些查询变体中的一个常见问题:针对未索引列的 MAX 将能够搭载聚集索引扫描并执行流聚合,而 >TOP 1 需要执行成本更高的排序。

我进行了测试,并在测试 b+d、e+g 和 f+h 时看到了完全相同的结果。

因此,在我看来,除了生成更多符合标准的代码之外,使用 MAX 代替 TOP 1 还具有潜在的性能优势,具体取决于基础表和索引(在将代码投入生产后可能会发生变化)。所以我想说,如果没有更多信息,MAX 更可取。

(正如我之前所说,如果您要拉取其他列,TOP 1 可能确实是您所追求的行为。您需要测试 MAX + JOIN 方法,如果这就是您想要的。)

关于SQL 性能 MAX(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11285388/

相关文章:

performance - 电梯应用性能下降

mysql - Laravel 是否可以合并 3 个选择查询

asp.net - 如何配置 SQL Server 使其与带有 Windows 身份验证的 ASP.NET MVC 一起使用?

sql-server - 将 CSV 字符串与 IN 运算符一起使用时出错

sql-server - 如何将 XML 查询结果保存到文件

php - Laravel PHP foreach(User::all() as $user) 性能

performance - 为什么在 AWS S3 中删除对象比创建对象慢这么多?

sql - Oracle 检查约束

sql - Oracle 查询 - 仅获取选择字段中的字符串

mysql - 如何将 DISTINCT 与 JOIN 结合使用?