【问题标题】:Understanding a SQL Server execution plan了解 SQL Server 执行计划
【发布时间】:2021-12-09 23:23:25
【问题描述】:

我使用以下查询来查看 SQL Server 执行计划。

SELECT TOP 1000
    fact.division,
    case when fact.division='east' then 'XXX' else 'YYY' end div,
    count(1)
FROM
    division join fact on (division.division=fact.division) 
where
    fact.division!='east'
group by
    fact.division

计划如下:

我有几个关于计划的问题:

  1. 为什么要在聚合之前进行排序?
  2. 这两个流聚合操作有什么用?我可以理解在加入后做一个,但为什么要两个?
  3. 最后,这两个“计算标量”是干什么用的?当我将鼠标悬停在它们上方时,我期待它会告诉我一些类似于“这是CASE 声明”的内容,但它们非常不透明。我如何知道“计算标量”在做什么?

【问题讨论】:

标签: sql sql-server sql-execution-plan


【解决方案1】:
  1. 为什么要在聚合之前进行排序?

流聚合要求输入按group by 列排序。这样,它会一起接收一个组的所有行,并且当它看到它已完成处理它的所有行时,它可以发出该组的聚合总数(并重置下一组的聚合)。

  1. 这两个流聚合操作有什么用?我可以理解在加入后做一个,但为什么要两个?

SQL Server 可以做的一个优化是在连接之前进行部分聚合以减少进入连接的行数,然后在连接之后计算最终总数。如果fact 有三行division = 'west' 它可以将其折叠到1 行并传递值3。然后它只需要在内部连接表中进行一次查找而不是 3。然后它可以对连接结果求和以获得最终总数(即,如果 division 有 2 个匹配行。3 和 @ 的 SUM 987654329@是6)

在 SSMS 中选择运算符并查看“属性”窗口 (F4) 以查看两个流聚合的“定义值”。

连接右边的有表达式

[partialagg1008] = Scalar Operator(Count(*))

加入之后的那个有

[globalagg1009] = Scalar Operator(SUM([partialagg1008]))
  1. 最后,这两个“计算标量”是干什么用的?当我将鼠标悬停在它们上方时,我期待它会告诉我一些类似于“这是CASE 声明”的内容,但它们非常不透明。我如何知道“计算标量”在做什么?

您还需要查看这些定义的值。

其中一个具有表达式[Expr1006] = Scalar Operator(CONVERT_IMPLICIT(int,[globalagg1009],0)),并将COUNT 聚合的结果转换回int。在内部 COUNTCOUNT_BIG 使用返回 bigint 的相同设备 - 对于 COUNT 这需要强制转换才能获得最终的广告数据类型。

另一个是计算你的CASE表达式的结果,表达式为[Expr1007] = Scalar Operator(CASE WHEN [avails].[dbo].[fact].[Division]=N'east' THEN 'XXX' ELSE 'YYY' END)

【讨论】:

  • 我很惊讶CASE 没有使用动态切片进行优化(即它应该意识到Division 不能是'east')。据我所知,SQL Server 的编译器通常会这样做
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多