包含大量 ComputeScalar 操作的执行计划

DBK*_*DBK 4 sql-server execution-plan recompile query-performance

我在使用和不使用 OPTION (RECOMPILE) 的情况下执行了相同的查询。当我比较这两个计划时,我看到的一个主要区别是,没有选项重新编译的计划显示了很多 ComputeScalar 运算符,而另一个则没有。

以下是两个计划:

不带选项重新编译:https://www.brentozar.com/pastetheplan/ ?id=S1OcZGi85 带选项重新编译:https://www.brentozar.com/pastetheplan/ ?id=ryJAfMsL5

为什么一个计划使用大量计算标量,而另一个计划则不使用?不带选项重新编译的查询需要近 4 分钟才能执行。计算标量操作是否导致速度缓慢?

Cha*_*ace 5

编译器正在采用您的IN子句并尝试通过删除重复值来进行优化。它通过获取所有参数、对它们进行排序、使用 来按顺序合并它们Merge Interval,并对Nested Loop Join结果执行 a 操作来实现此目的。

问题是,这可能需要很长的时间来编译大量值:每个值都需要自己的虚拟表,导致最后出现 aConstant Scan和 aCompute Scalar以及一个 big 值。Concatenation这就是在运行查询之前导致编译时速度减慢的原因。

同时,该OPTION (RECOMPILE)版本可以将参数直接嵌入到查询中,这意味着在编译的优化阶段开始之前这些值将被折叠在一起,从而显着加快整体编译时间。这是以每次运行时重新编译为代价的。

所有这一切的结果是IN,很长的列表以及大量的参数可能会非常低效。

我建议您考虑使用表值参数、临时表或表变量(在所有情况下都使用主集群键进行索引),并以正常方式简单地加入它们。


至于实际的查询本身,有很多奇怪的事情。

  • 你的最终结果是这样COUNT(*)的,所以不清楚巨人PIVOT最初的意义是什么,相对于正常的GROUP BY.
  • 同样,也不清楚为什么大多数表格都在那里,或者最终结果应该意味着什么。
  • 一旦你解决了这个问题,为什么LEFT JOIN不呢INNER JOIN?连接列可以为空吗?
  • 实际上并CROSS APPLY没有应用任何外部引用,它可能是CROSS JOIN,并且其本身在查询中没有任何作用。