为什么并行(重新分区流)运算符会将行估计减少到 1?

Joh*_*ner 12 sql-server execution-plan sql-server-2012 cardinality-estimates

我正在使用 SQL Server 2012 企业版。我遇到了一个 SQL 计划,它表现出一些我认为并不完全直观的行为。在执行大量并行索引扫描操作后,会发生并行(重新分区流)操作,但它会终止索引扫描 (Object10.Index2) 返回的行估计值,将估计值减少到 1。我已经进行了一些搜索,但是没有遇到任何可以解释这种行为的东西。查询非常简单,尽管每个表都包含数百万的记录。这是 DWH 加载过程的一部分,这个中间数据集在整个过程中被触及了几次,但我的问题特别与行估计有关。有人可以解释为什么在并行(重新分区流)运算符中准确的行估计值变为 1?还,

我已将完整计划发布到Paste the Plan

这是有问题的操作:

在此处输入图片说明

包括计划树,以防添加更多上下文:

在此处输入图片说明

我能运行到的一些变化这个连接项目由保罗·怀特(进一步深入explination在自己的博客提交这里)?至少这是我发现的唯一一个似乎与我遇到的情况非常接近的东西,即使没有 TOP 运算符在起作用。

Joe*_*ish 9

带有位图过滤器的查询计划有时难以阅读。来自重新分区流的 BOL 文章(重点是我的):

Repartition Streams 运算符使用多个流并生成多个记录流。记录内容和格式不变。如果查询优化器使用位图过滤器,则输出流中的行数会减少。

另外,一篇关于位图过滤器的文章也很有帮助:

在分析包含位图过滤的执行计划时,了解数据如何流经计划以及在哪里应用过滤非常重要。位图过滤器和优化位图是在散列连接的构建输入(维度表)侧创建的;然而,实际的过滤通常是在 Parallelism 运算符中完成的,它位于散列连接的探测输入(事实表)一侧。但是,当位图过滤器基于整数列时,过滤器可以直接应用于初始表或索引扫描操作,而不是 Parallelism 运算符。这种技术称为行内优化。

我相信这就是您在查询时所观察到的。可以想出一个相对简单的演示来展示减少基数估计的重新分区流运算符,即使位图运算符IN_ROW与事实表相对。数据准备:

create table outer_tbl (ID BIGINT NOT NULL);

INSERT INTO outer_tbl WITH (TABLOCK)
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values;

create table inner_tbl_1 (ID BIGINT NULL);
create table inner_tbl_2 (ID BIGINT NULL);

INSERT INTO inner_tbl_1 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

INSERT INTO inner_tbl_2 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Run Code Online (Sandbox Code Playgroud)

这是您不应运行的查询:

SELECT *
FROM outer_tbl o
INNER JOIN inner_tbl_1 i ON o.ID = i.ID
INNER JOIN inner_tbl_2 i2 ON o.ID = i2.ID
OPTION (HASH JOIN, QUERYTRACEON 9481, QUERYTRACEON 8649);
Run Code Online (Sandbox Code Playgroud)

我上传了计划。看看附近的运营商inner_tbl_2

重新分区丢失行

您可能还会发现Paul White在可空列上的哈希联接中的第二个测试很有帮助。

在如何应用行减少方面存在一些不一致之处。我只能在至少有三张桌子的计划中看到它。但是,在正确的数据分布下,预期行的减少似乎是合理的。假设事实表中的联接列有许多维表中不存在的重复值。位图过滤器可能会在这些行到达连接之前将其删除。对于您的查询,估计值一直减少到 1。行在散列函数中的分布方式提供了一个很好的提示:

行发行版

基于此,我怀疑您对该Object1.Column21列有很多重复的值。如果重复的列碰巧不在统计直方图中,Object4.Column19那么 SQL Server 的基数估计可能会非常错误。

我认为您应该担心可能会提高查询的性能。当然,如果查询满足响应时间或 SLA 要求,则可能不值得进一步调查。但是,如果您确实希望进一步调查,您可以做一些事情(除了更新统计数据)来了解查询优化器是否会选择更好的计划,如果它有更好的信息。你可以把结果之间的连接Database1.Schema1.Object10,并Database1.Schema1.Object11与到一个临时表看,如果你继续得到嵌套循环联接。您可以将该连接更改为 a,LEFT OUTER JOIN以便查询优化器不会减少该步骤的行数。您可以MAXDOP 1向查询添加提示以查看会发生什么。你可以用TOP连同派生表以强制连接最后进行,或者您甚至可以从查询中注释掉连接。希望这些建议足以让您入门。

关于问题中的连接项,它极不可能与您的问题有关。这个问题与糟糕的行估计无关。它与并行中的竞争条件有关,该条件导致后台查询计划中处理过多行。看起来您的查询没有做任何额外的工作。


Pau*_*ite 6

这里的核心问题是对第一次连接结果的基数估计不佳。这可能有多种原因,但最常见的是过时的统计数据或大量相关的连接谓词,优化器的默认模型假定它们是独立的。

在后一种情况下,FIX:在 SQL Server 2008 或 SQL Server 2008 R2 或 SQL Server 2012 中运行包含相关 AND 谓词的查询时性能不佳可能与使用支持的跟踪标志 4137 相关。您也可以尝试使用该查询跟踪标志 4199 以启用优化器修复,和/或 2301 以启用建模扩展。根据匿名计划很难知道。

位图的存在不会直接影响连接的基数估计,但通过应用早期的半连接减少确实可以使其效果更快地显现出来。如果没有位图,第一个连接的基数估计将是相同的,并且计划的其余部分仍会相应地进行优化。

如果您好奇,在测试系统上,您可以使用跟踪标志 7498 禁用查询的位图。您还可以禁用优化位图(由优化器考虑并影响基数估计),将它们替换为优化后位图(未考虑)由优化器,对基数没有影响)与跟踪标志 7497 和 7498 的组合。两者都没有记录或支持在生产系统上使用,但它们确实生成优化器可以正常考虑的计划,因此可以强制计划指南。

这些都不能解决上面提到的第一次加入的错误估计的核心问题,所以我真的只是为了利益才提到它。

进一步阅读位图和哈希连接: