我有2个查询:一个有TOP子句,一个没有。结果完全相同,但TOP子句的结果明显变慢。为什么会这样?
服务器:Microsoft SQL Server 2008 R2(SP2)
查询1 - 常规
insert into #Buffer (details, persistentID, productID, [date])
select de.details, lg.databaseID % 1000, lg.productID, lg.readDateTime
from Log lg with (nolock)
join LogDetails de with (nolock)
on lg.logID = de.logID
where @startDate <= readDateTime and readDateTime < @endDate
查询2 - TOP子句
insert into #Buffer (details, persistentID, productID, [date])
select top (@count) de.details, lg.databaseID % 1000, lg.productID, lg.readDateTime
from Log lg with (nolock)
join LogDetails de with (nolock)
on lg.logID = de.logID
where @startDate <= readDateTime and readDateTime < @endDate
注意@count
是结果集的大小。
奇怪的是,查询2的CPU时间是查询1的一半,但查询2的经过时间是查询1的3倍。
答案 0 :(得分:2)
基于此:Inside the Optimizer: Row Goals In Depth来自Paul White
当您向SQLServer提出查询时,它会假设您将消耗查询生成的所有行。但是有时,当您引入TOP和EXISTS运算符时,SQL服务器将尝试查找第一行尽快,这有时会导致较少的最优计划。在你的情况下,它会导致嵌套循环计划..
你可能会问为什么这一行目标,无法优化......下面是保罗怀特对此的解释。
为行限制查询生成优化查询计划所涉及的挑战,同时保留完整结果查询的良好通用优化性能,比简单地用嵌套循环替换散列或合并连接迭代器更复杂。使用设计用于识别特定方案的特定代码来满足计划根目录中的TOP的查询将是相当简单的。但是,在更一般的情况下,这种方法会错过更广泛的计划优化机会。
可以在查询声明的多个位置多次指定TOP子句:在最外层范围内(如示例中所示);在子查询中;或者在一个公用表格中 - 所有这些都可能是任意复杂的。 FAST'n'查询提示也可用于要求优化器更喜欢快速生成第一个'n'行的计划,而不限制整体返回的总行数,如TOP的情况。作为最后一个例子,考虑逻辑半连接(例如用EXISTS引入的子查询)共享整个主题:应该优化它以快速找到第一个匹配的行。
SQL Server查询优化器提供了一种满足所有这些要求的方法,它引入了“行目标”的概念,该行目标只是在计划的特定点上建立了一些“目标”行。
因此,在您的情况下,要克服此ROWGOAL
限制,您可以使用提示重写下面的查询
insert into #ViewCountBuffer (details, persistentID, productID, [date])
select top (@count) details, databaseID % 1000, productID, readDateTime
from Log ld with (nolock)
HASH join LogDetails de with (nolock)
on ld.logID = de.logID
where @startDate <= readDateTime and readDateTime < @endDate
以下是相同主题的堆栈Exchange上的相关主题,..
https://dba.stackexchange.com/questions/157353/wrapping-query-in-if-exists-makes-it-very-slow
https://dba.stackexchange.com/questions/24832/how-and-why-does-top-impact-an-execution-plan