刚刚得到一个小问题。 当试图得到一个表的单个最大 - 值。 哪一个更好?
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
我使用的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
在我的系统中,通过一个/ C这个创建的值从1至50000,B / 3和9994,E / G之间从2010-01-01 2011-05-16通过F / H从2009-04-28 d,和2012-01-01。
首先,让我们比较索引单调递增的整数列,a和c。 一个有聚簇索引,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
方法,以及如果这就是你以后)。
第一个是在一定的意图更清晰。
不应该有想过这个特定的查询(他们实际上应该是几乎相同的,即使结果是不同的,如果有在任何行显著的性能差异myTable
)。 除非你有正当理由,以调整查询(例如一个行之有效的性能问题),总是挑一个,显示了代码的意图。
所有查询优化称职应该产生与这两个查询相同的性能查询计划:如果没有被优化的列的索引,这两个查询应该使用它; 如果没有索引,既会产生全表扫描。
虽然我怀疑TOP 1排序操作是在计划中的成本核算。 我试着用TOP 1,TOP 100>和TOP 101和全部给了我同样预计子树成本尽管最后一>将需要所有行进行排序。 - 马丁·史密斯07月02日6:53时
无论您需要1行或100行优化需要做的工作相同数量在这个例子中,即读取所有从表(聚集索引扫描)的行。然后排序所有行(排序opertaion),因为是在没有索引柱C..Finally只是显示需要哪一个。
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);
尝试上面的代码和这里顶部1和顶部100示出了差速器的成本,因为存在对B列的索引。 因此,在这种情况下,你不需要读取所有的行和排序他们,但工作是要到最后一页pointer.For一个行读取索引的最后一片叶子页的最后一行。 TFor 100行找到最后一页的最后一行,然后开始反向扫描,直到你得到的100行。