我从SQL Server(2005)获得了一个奇怪的执行计划行为。
TableName:日志
...包含大约1000行
查询:
SELECT *
FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) as Row,
ID, Name
FROM Log) AS LogWithRowNumbers
WHERE Row >= 1
AND Row <= 2
它估计返回的行数为9(虽然它明显为2或更少) 此外,删除“和行&lt; = 2”将使执行时间增加约* 5.(“和行&lt; = 2”和“和&lt; = 9999999999999”行为相同)
我已更新统计数据。但是,这种行为很奇怪。添加行&lt; 99999999999将使查询运行得更快?为什么?
答案 0 :(得分:6)
我不是SQL Server内部工作/查询优化过程的专家,但这是我的2便士(如果你愿意的话还是美分)。
我认为这是由于在WHERE子句中使用了ROW_NUMBER()值。作为一个例子,我创建了一个样本表,填充了从ID 1到1000的1000行(ID作为主键),就像你说的那样。
如果您取出ROW_NUMBER(),并根据ID列执行查询,如下所示:
Select * FROM
(
SELECT ID, Name
FROM Log
)
as LogWithRowNumbers
WHERE ID>=1 and ID<=2
然后它正确显示行数为2 - 正如预期的那样。
现在,向后工作,将ROW_NUMBER添加到内部SELECT,但保留WHERE子句,如下所示:
Select * FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) AS RowNo,
ID, Name
FROM Log
)
as LogWithRowNumbers
WHERE ID>=1 AND ID <=2
这仍然显示正确的行数为2。
最后,将WHERE子句重新设置为使用RowNo作为要过滤的列而不是ID,这是估计行数跳到9时。
因此,我认为它是使用ROW_NUMBER()函数,在作为原因的WHERE子句中进行过滤。所以我想这是因为实际表列上有明显更好/更准确的统计数据,而不是这个函数产生的值。
我希望这至少提供了一个很好的起点,希望有用!
答案 1 :(得分:2)
AdaTheDev是对的。您看到此行为的原因是因为SQL Server必须先计算表的行号才能在where子句中使用它们。
这应该是获得相同结果的更有效方式:
SELECT TOP(2) ROW_NUMBER() OVER (ORDER BY ID DESC) as Row,
ID, Name
FROM Log
ORDER BY ID DESC