流聚合排序?

jes*_*esi 5 performance sql-server sql-server-2008-r2 cardinality-estimates query-performance

在此处输入图片说明

试图理解上述查询计划中的几件事。

  • 当我没有 group by 时,为什么查询中有一个 Stream Aggregate。我猜这与合并的连接及其进行排序有关?

  • 其次,更重要的是,为什么 13
    进入流聚合的估计结果是 24,595,900?这导致了 Object4 获取聚集索引而不是嵌套循环的次要问题。我不得不将查询拆分为两个查询,而不是使用 OR,并且连接变成嵌套循环并查找到 Object4。

查询计划

https://www.brentozar.com/pastetheplan/?id=BJk2eFLul

Joe*_*ish 8

回答你的第一个问题:

当我没有 group by 时,为什么查询中有一个 Stream Aggregate。我猜这与合并的连接及其进行排序有关?

SQL Server 正在有效地重写您的查询。这个查询:

select Object1.Column1
FROM Object2 Object3 WITH (ROWLOCK)
INNER JOIN Object4 Object1 WITH (ROWLOCK) ON Object3.Column2 = Object1.Column1
WHERE Object3.Column2 in (SELECT Column2 FROM Object5)
or Object3.Column3 in (SELECT Column2 FROM Object5);
Run Code Online (Sandbox Code Playgroud)

也可以这样写:

select Object1.Column1
FROM
(
select Object3.Column2
FROM Object2 Object3 WITH (ROWLOCK)
WHERE Object3.Column2 in (SELECT Column2 FROM Object5)

UNION

select Object3.Column2
FROM Object2 Object3 WITH (ROWLOCK)
WHERE Object3.Column3 in (SELECT Column2 FROM Object5)
) Object3 
INNER JOIN Object4 Object1 WITH (ROWLOCK) ON Object3.Column2 = Object1.Column1;
Run Code Online (Sandbox Code Playgroud)

这就是为什么Object2在查询计划中有两种不同的访问方法。该Merge Join (Concatenation)操作实际上不是合并连接。它只是实现 aUNION ALL并结合结果。您提到的流聚合分组为Object3.Column2。这既可以从 中删除重复项Merge Join (Concatenation),又可以对数据进行排序,以便它可以在接下来MERGE JOIN的 Object4 中使用。

回答你的第二个问题:

其次,更重要的是,为什么 13 进入流聚合的估计结果是 24,595,900?这导致了 Object4 获取聚集索引而不是嵌套循环的次要问题。我不得不将查询拆分为两个查询,而不是使用 OR,并且连接变成嵌套循环并查找到 Object4。

它看起来像一个错误。经过一番搜索,我找到了 Paul White 的一篇文章,解释了这个问题。如果您想为其投票或将自己添加为受影响的人,则会将该错误报告给Connect

简而言之,基数估计为 24595900,因为四舍五入后 27328800(表基数Object2)* 0.9 = 24595900。您使用的是 SQL Server 2008,因此使用旧版 CE 计算:

2014 年之前的基数估计器也存在类似问题,但最终估计值固定为估计半连接输入的 90%(出于娱乐性原因,与反向固定 10% 谓词估计值有关,这太分散了,无法获得进入)。

我建议通读整篇文章。这个问题有点难以总结,但我将尝试通过引用接近结尾的部分文字来做到这一点:

基数估计器使用具有 100% 选择性的固定连接计算器。因此,半连接的估计输出基数与其输入相同,这意味着历史表中的所有 113443 行都应符合条件。

该错误的确切性质是半连接选择性计算错过了输入树中所有位于 union all 之外的谓词。在下图中,半连接本身缺少谓词意味着每一行都符合条件;它忽略连接(union all)下面的谓词的影响。

2014 年之前的基数估计器也存在类似问题,但最终估计值固定为估计半连接输入的 90%(出于娱乐性原因,与反向固定 10% 谓词估计值有关,这太分散了,无法获得进入)。

像您一样拆分查询应该可以防止出现此问题。您也可能通过使用重写查询来获得一些运气UNION(请参阅文章中的示例 4)。