在下面的查询计划片段中,很明显Concatenation
运算符的行估计应该是~4.3 billion rows
,或者它的两个输入的行估计的总和。
但是,生成了 的估计值~238 million rows
,导致次优Sort
/Stream Aggregate
策略将数百 GB 的数据溢出到 tempdb。在这种情况下,逻辑上一致的估计会产生Hash Aggregate
,消除溢出,并显着提高查询性能。
这是 SQL Server 2014 中的错误吗?在任何有效情况下,低于输入值的估计值是合理的吗?可能有哪些解决方法?
这是完整的查询计划(匿名)。我没有系统管理员访问此服务器的权限,无法提供来自QUERYTRACEON 2363
或类似跟踪标志的输出,但如果有用的话,我可以从管理员那里获得这些输出。
该数据库的兼容级别为 120,因此使用新的 SQL Server 2014 基数估算器。
每次加载数据时都会手动更新统计信息。鉴于数据量,我们目前使用默认采样率。较高的采样率(或FULLSCAN
)可能会产生影响。
在此 Connect 项目上引用 Campbell Fraser 的话:
稍微扩展一下:我喜欢解释的方式是说初始基数估计(在基于成本的优化开始之前执行)产生更“一致”的基数估计,因为整个初始树都被处理,每个后续估计直接取决于前一个。
在基于成本的优化过程中,计划树的一部分(一个或多个运算符)可能会被探索并替换为备选方案,每个备选方案都可能需要新的基数估计。没有通用的方法可以说明哪个估计通常比另一个更好,因此很有可能最终得出一个看起来“不一致”的最终计划。这只是将“部分计划”拼接在一起形成最终安排的结果。
总而言之,SQL Server 2014 中引入的新基数估计器 (CE) 有一些详细的更改,这使得这种情况比原始 CE 的情况要少一些。
除了升级到最新的累积更新并检查 4199 的优化器修复是否打开之外,您的主要选择是尝试统计/索引更改(注意缺少索引的警告)和更新,或者以不同的方式表达查询。目标是获得一个显示您需要的行为的计划。例如,这可能会被计划指南冻结。
匿名计划很难评估细节,但我也会仔细查看位图,看看它们是否属于“优化”(Opt_Bitmap) 或优化后 (Bitmap) 类型。我也怀疑过滤器。
不过,如果行计数准确的话,这似乎是一个可能受益于列存储的查询。除了通常的好处之外,您还可以利用批处理模式运算符的动态内存授予(可能需要跟踪标志 9389 )。
在 SQL Server 2012 (11.0.6020) 上构建一个公认的相当简单的测试平台允许我重新创建一个计划,其中两个哈希匹配查询通过
UNION ALL
. 我的测试台不会显示您看到的错误估计。也许这是SQL Server 2014 CE 的问题。对于实际返回 280 行的查询,我估计有 133.785 行,但是这是可以预料的,因为我们将在下面进一步看到:
我认为原因在于缺少两个联合的结果连接的统计信息。在大多数情况下,当面对缺乏统计信息时,SQL Server 需要围绕列的选择性进行有根据的猜测。
Joe Sack 在这里读了一篇有趣的文章。
对于 a
UNION ALL
,可以肯定地说我们将准确地看到联合的每个组件返回的总行数,但是由于 SQL Server 正在对 的两个组件使用行估计UNION ALL
,我们看到它添加了两个组件的总估计行数查询以得出串联运算符的估计值。在我上面的例子中,每个部分的估计行数
UNION ALL
是 66.8927,加起来等于 133.785,我们看到连接运算符的估计行数。上面联合查询的实际执行计划如下所示:
您可以看到“估计”与“实际”行数。在我的例子中,将两个哈希匹配运算符返回的“估计”行数相加恰好等于串联运算符显示的数量。
我会尝试按照您在问题中显示的 Paul White 帖子中的建议从跟踪 2363 等获取输出。或者,您可以尝试
OPTION (QUERYTRACEON 9481)
在查询中使用恢复到版本 70 CE以查看是否“修复”了问题。