Vla*_*sak 3 sql-server execution-plan
这是现实生活问题的简化版本。GetDate
在子选择中使用时,计划更糟且不同。2个查询:
select * , (select count(1)
from hamsfa.customer as sub
where sub.tstamp_nosync > @old
and sub.cus_id > main.cus_id) as x
from hamsfa.customer as main ;
select * , (select count(1)
from hamsfa.customer as sub
where sub.tstamp_nosync > dateadd(year, -100, getdate())
and sub.cus_id > main.cus_id) as x
from hamsfa.customer as main ;
Run Code Online (Sandbox Code Playgroud)
我不完全理解的是为什么。
变量应该按我的理解变差。
还有另一个查询,这导致了几乎 700% 的差异(1s 与 7s)。
所以问题是:为什么一个变量会产生更好的计划,即使根据我的经验它应该更糟?
编辑:统计数据是最新且正确的
当您使用该变量时,SQL Server 会猜测tstamp_nosync
谓词的选择性 。对于>
操作员,猜测是 30%。该表包含 3052 行,因此估计猜测 3052 = 915.6 行中的 30% 将通过该测试。
当您使用该dateadd(year, -100, getdate())
表达式时,SQL Server 可以对符合该谓词的行数进行更准确的估计。
您的 SQL Server 2012 版本没有Actual Rows Read 属性,因此实际匹配的行数在您的第二个计划中不可用。该功能是在 SQL Server 2012 的 Service Pack 3 中添加的(出于某种原因,您仍在使用 Service Pack 1)。
据我所知,对dateadd
表达式的更好估计是所有行都符合条件。这从第一个计划中的 Eager Index Spool 的输出中可以明显看出。3052 行使用tstamp_nosync
谓词测试 3052 次(嵌套循环连接的每次迭代一次),并且全部通过。结果是总共 3052 * 3052 = 9,314,704 行。这显示为线轴中的实际行数:
使用变量会导致更糟糕的执行计划的普遍预期是合理的,因为具体的估计通常比完全猜测更准确;但是,sub.cus_id > main.cus_id
查询中的另一个谓词将始终导致 30% 的猜测。
对于变量查询,两个谓词都是用 30% 的猜测估计的。组合估计为 3052 * 30% * 30% = 274.68 行(见于流聚合的输入):
对于dateadd
查询,有一个 30% 的猜测(寻求谓词)和一个 100% 的选择性估计(残差谓词),如前所述,给出了 915.6 行的组合估计。该估计值显示在聚集索引搜索的输出中:
估计的差异解释了优化器的不同计划选择。
为可变案例估计的行越少,估计成本就越低。出于类似的原因,更好的估计成本更高。然而,由于cus_id
谓词中涉及的猜测,这两个计划都基于不准确的估计。
在观察到的性能方面,哪个计划执行得更好,而取决于您当地环境的细节。变量计划扫描源表一次并在tempdb 中构建索引临时表。非变量计划每次都通过搜索(猜测 30% 的选择性)和剩余谓词(计算的 100% 选择性)简单地访问基表。在实践中哪个表现更好取决于多种因素。
给定两个谓词的正确信息,优化器更有可能生成在实践中更好的计划。
非常注意数据类型通常是值得的。datetime2(4)
在您的执行计划中有一个隐式转换,因为这是列的类型,而变量是别的东西(datetime
也许)。dateadd
表达式的结果也是datetime
,也需要隐式转换。在这种特定情况下,这种转换似乎并不重要,但通常很重要。例如,请参阅:
性能惊喜和假设:DATEADD()
Aaron Bertrand。
归档时间: |
|
查看次数: |
386 次 |
最近记录: |