没有区别,因为您可以通过检查执行计划来测试自己。如果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;
结果:
第四个查询的最大问题是,与MAX 不同,它需要排序。这是 3 与 4 的对比:
这将是所有这些查询变体中的一个常见问题:针对未索引列的 MAX 将能够搭载聚集索引扫描并执行流聚合,而 TOP 1 需要执行排序会更贵。
我进行了测试,并在测试 b+d、e+g 和 f+h 中看到了完全相同的结果。
所以在我看来,除了生成更多符合标准的代码之外,使用 MAX 而不是 TOP 1 还具有潜在的性能优势,具体取决于基础表和索引(在您使用之后可能会发生变化) '已将您的代码投入生产)。所以我想说,如果没有更多信息,MAX 更可取。
(正如我之前所说,TOP 1 可能真的是你所追求的行为,如果你要拉更多的列。你会想要测试 MAX + JOIN 方法,如果那是什么你在追求。)