一尘不染

为什么串联运算符估计的行数少于其输入的行数?

sql-server

在下面的查询计划片段中,很明显Concatenation运算符的行估计应该是~4.3 billion rows,或者它的两个输入的行估计的总和。

但是,生成了 的估计值~238 million rows,导致次优Sort/Stream Aggregate策略将数百 GB 的数据溢出到 tempdb。在这种情况下,逻辑上一致的估计会产生Hash Aggregate,消除溢出,并显着提高查询性能。

这是 SQL Server 2014 中的错误吗?在任何有效情况下,低于输入值的估计值是合理的吗?可能有哪些解决方法?

在此处输入图像描述

这是完整的查询计划(匿名)。我没有系统管理员访问此服务器的权限,无法提供来自QUERYTRACEON2363或类似跟踪标志的输出,但如果有用的话,我可以从管理员那里获得这些输出。

该数据库的兼容级别为 120,因此使用新的 SQL Server 2014 基数估算器。

每次加载数据时都会手动更新统计信息。鉴于数据量,我们目前使用默认采样率。较高的采样率(或FULLSCAN)可能会产生影响。


阅读 95

收藏
2022-11-23

共1个答案

一尘不染

在此 Connect 项目上引用 Campbell Fraser 的话:

这些“基数不一致”可能出现在许多情况下,包括使用 concat 时。它们之所以会出现,是因为对最终计划中特定子树的估计可能是在结构不同但逻辑上等效的子树上执行的。由于基数估计的统计性质,在不同但逻辑上等价的树上进行估计并不能保证得到相同的估计。所以总体上没有提供预期一致性的保证。

稍微扩展一下:我喜欢解释的方式是说初始基数估计(在基于成本的优化开始之前执行)产生更“一致”的基数估计,因为整个初始树都被处理,每个后续估计直接取决于前一个。

在基于成本的优化过程中,计划树的一部分(一个或多个运算符)可能会被探索并替换为备选方案,每个备选方案都可能需要新的基数估计。没有通用的方法可以说明哪个估计通常比另一个更好,因此很有可能最终得出一个看起来“不一致”的最终计划。这只是将“部分计划”拼接在一起形成最终安排的结果。

总而言之,SQL Server 2014 中引入的新基数估计器 (CE) 有一些详细的更改,这使得这种情况原始 CE 的情况要少一些。

除了升级到最新的累积更新并检查 4199 的优化器修复是否打开之外,您的主要选择是尝试统计/索引更改(注意缺少索引的警告)和更新,或者以不同的方式表达查询。目标是获得一个显示您需要的行为的计划。例如,这可能会被计划指南冻结。

匿名计划很难评估细节,但我也会仔细查看位图,看看它们是否属于“优化”(Opt_Bitmap) 或优化后 (Bitmap) 类型。我也怀疑过滤器。

不过,如果行计数准确的话,这似乎是一个可能受益于列存储的查询。除了通常的好处之外,您还可以利用批处理模式运算符的动态内存授予(可能需要跟踪标志 9389 )。

2022-11-23