Joe*_*ish 12 sql-server parallelism sql-server-2019 query-performance
我正在针对 SQL Server 2019 CU14 进行测试。我有一个纯行模式查询,它从复杂的视图中选择前 50 行。完整查询在 MAXDOP 1 时需要 25426 毫秒的 CPU 时间,在 MAXDOP 2 时需要 19068 毫秒的 CPU 时间。并行查询总体上使用较少的 CPU 时间并不令我感到惊讶。并行查询适用于位图运算符,并且查询计划在一些方面有所不同。然而,令我惊讶的是前 N 个排序的操作员时间的巨大差异。
在串行计划中,根据运算符执行统计数据,前 N 个排序占用了大约 10 秒的 CPU 时间:
MAXDOP 2 计划报告相同的前 N 排序大约需要 1.6 秒的 CPU 时间:
我不明白为什么两个不同的查询计划之间会报告如此大的差异。父运算符中的计算标量非常简单,无法解释运算符时间的差异。它们是这样的:
[Expr1055] = Scalar Operator(CASE WHEN COLUMN_1 IS NULL THEN (0) ELSE datediff(day,COLUMN_1,getdate()) END),
[Expr1074] = Scalar Operator(CASE WHEN [Expr1074] IS NULL THEN (0) ELSE [Expr1074] END)
Run Code Online (Sandbox Code Playgroud)
计划的不同部分还有其他计算标量。我上传了匿名的实际计划如果有人想查看的话,
当我将不带 TOP 的完整查询结果加载到临时表中并对临时表执行 TOP 50 排序时,并行计划和串行计划都需要大约 1200 毫秒的 CPU 时间来执行排序。因此,在完整查询中报告的并行排序操作时间对我来说是合理的。串行查询的十秒则不然。
为什么串行前 N 排序报告的 CPU 时间比并行排序高得多?它的效率真的这么低吗?或者这可能是操作执行统计数据的错误?
Pau*_*ite 15
基于没有重现的匿名计划很难确定,但首先想到的机制是延迟表达评估。
在串行计划中,Sort可能负责评估从早期运算符推迟的大量表达式。这包括排序缓冲区中此时必须具体化的值,而不仅仅是排序键。因此,计算表达式的成本由 Sort 承担。
在并行计划中,可能必须提前评估这些表达式,例如,当必须在并行运算符的交换缓冲区中具体化值时。表达式求值的成本分散在计划运算符中,而不是集中在Sort上。
Sort处有大量表达式 (Exprxxxx) 。下面显示了一个选择(它们不能全部放在一个屏幕截图中):
我没有试图追踪其中哪一个可能负责,因为该计划的规模和匿名性质使得这是不可行的。
有许多运算符可以定义表达式,而不仅仅是计算标量。引用我之前链接的文章:
计算标量并不是唯一可以定义表达式的运算符。您可以在许多查询计划运算符中找到带有 [Expr1008] 等标签的表达式定义,包括常量扫描、流聚合...
表达式求值可以在许多运算符中延迟很长一段时间。关键点是计算被推迟,直到另一个运算符需要表达式的结果,或者甚至直到服务器需要组装行以返回给客户端。阻塞或半阻塞运算符只是可能需要具体化表达式求值的示例之一。
其他语言的用户可能熟悉“惰性求值”这个名称下的概念。计算在逻辑上尽可能延迟。
当然,在临时表中具体化结果意味着对所有表达式进行求值。这解释了为什么您会看到从临时表源执行的预期 CPU 时间。