想知道为什么这个查询执行缓慢。如果有人可以告诉我如何处理它将是伟大的。被查询的DB有超过5亿行。这个查询是否真的写得不好,以至于TOP 10需要很长时间才能完成它可能永远不会完成?假设我仍然想按月+年查询数据,我该如何改进查询?
SELECT TOP 10 *
FROM ADB.dbo.Stuff tt
WHERE MONTH(tt.SomeDate) = 5
AND
YEAR(tt.SomeDate) = 2011
在获得10个结果后,SELECT TOP 10不会停止吗?还是需要这么长时间,因为它在通过500米+行时还没有找到我的条件?
感谢并抱歉这么简单的问题。
答案 0 :(得分:7)
它必须扫描整个表,因为MONTH(column)
和YEAR(column)
不是可搜索的,并且您没有告诉SQL Server TOP
是什么意思。虽然SQL Server可能能够短路,但它找到了你的10行,但是当发生这种情况时,它可能会进入扫描范围,这对你来说差别很小。如果您发现零行或<0,则尤其如此。与where子句匹配的10行。
更好的WHERE
条款是:
WHERE SomeDate >= '20110501' AND SomeDate < '20110601';
如果您不想构造字符串,可以将它们作为参数/变量传递并执行此操作:
DECLARE @year INT;
DECLARE @month INT;
SET @year = 2011;
SET @month = 5;
...
WHERE SomeDate >= DATEADD(MONTH, @month-1, DATEADD(YEAR, @year-1900, '19000101'))
AND SomeDate < DATEADD(MONTH, @month, DATEADD(YEAR, @year-1900, '19000101'));
在任何一种情况下,如果SomeDate
上有索引,则可以使用它,并且可以避免表扫描。您希望避免在具有5亿行的表上进行表扫描,即使您只查找10行,即使可能发生短路。
然而,即使没有表扫描,此查询仍然效率低下。你真的需要所有的专栏吗?如果使用SomeDate
上的索引,则搜索仍然必须查找聚簇索引或覆盖索引以检索其余列。如果您不需要这些列,请不要包含它们。
正如bluefeet指出的那样,如果你没有告诉SQL Server 你的意思是哪个 10,那么这个TOP 10
的东西是没有意义的,而你使用ORDER BY
来做。如果ORDER BY
使用了合适的索引,您可以避免使用额外的代价高昂的排序运算符,您可能认为无论如何都不会使用ORDER BY
。