SELECT MAX(id) FROM myTable WHERE (whatever)
或者
SELECT TOP 1 id FROM myTable WHERE (whatever) ORDER BY id DESC
我正在使用Microsoft SQL Server 2012。
SELECT MAX(id) FROM myTable WHERE (whatever)
或者
SELECT TOP 1 id FROM myTable WHERE (whatever) ORDER BY id DESC
你可以通过检查执行计划来确定,这两种方法没有区别。如果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
在我的系统上,这将创建从1到50000的a/c值,3到9994之间的b/d值,以及从2010-01-01到2011-05-16的e/g值和从2009-04-28到2012-01-01的f/h值。
首先,让我们比较索引的单调递增整数列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;
结果:
第4个查询的主要问题是,与MAX
不同,它需要排序。这里是3和4的比较:
所有这些查询变体都会遇到一个常见问题:对未索引列的MAX
将能够利用聚集索引扫描并执行流式聚合,而TOP 1
需要执行更昂贵的排序操作。
我进行了测试,并在测试b + d、e + g和f + h时看到了完全相同的结果。
因此,在我看来,除了产生更多符合标准的代码外,根据底层表格和索引(在将代码投入生产后可能会发生变化),使用MAX
而不是TOP 1
可能会带来潜在的性能优势。因此,如果没有其他信息,我会说MAX
更可取。
(正如我之前所说的,如果你拉取额外的列,TOP 1
可能真的是你想要的行为。如果你真的需要这个结果,你还需要测试MAX
+JOIN
方法。)
myTable
中没有行时结果是不同的,它们实际上应该几乎相同)。除非你有充分的理由来调整查询(例如已经证明存在性能问题),否则总是选择显示代码意图的那个。所有值得信赖的查询优化器都应该生成性能相同的查询计划:如果正在优化的列上有索引,则两个查询都应使用它;如果没有索引,则两个查询都会产生全表扫描。
SELECT TOP (1) b FROM dbo.x ORDER BY b DESC
option(recompile);
SELECT TOP (100) b FROM dbo.x ORDER BY b DESC
option(recompile);
TOP 1
不会这样做,但 TOP 101
会。这在我链接的帖子中很清楚。然而,尽管 TOP 1
做的工作明显较少,但估计的子树成本并没有显示出任何成本差异,这是我的原始陈述。 - Martin SmithO(n)
复杂度。对所有行进行排序具有O(n log n)
复杂度。 - Martin Smith
id
是自增的,那么这个问题是https://dev59.com/A3RB5IYBdhLWcg3wj32c的重复。 - Ben