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


12

我正在使用SQL Server 2012 Enterprise。我遇到了一个SQL计划,该计划表现出一些我不完全直观的行为。在执行大量并行索引扫描操作之后,发生了并行(分区流)操作,但是该操作杀死了索引扫描(Object10.Index2)返回的行估计,从而将估计值减小为1。我已经做了一些搜索,但是还没有遇到任何可以解释这种现象的信息。查询非常简单,尽管每个表都包含数百万的记录。这是DWH加载过程的一部分,整个中间数据集都被触及过几次,但是我遇到的问题尤其与行估计有关。有人可以解释为什么并行(Repartition Strems)运算符中的精确行估计为1吗?也,

我已经发布了完整的计划以粘贴计划

这是有问题的操作:

在此处输入图片说明

在添加更多上下文的情况下包括计划树:

在此处输入图片说明

我能否碰到Paul White提交的Connect项目的一些变体(在此处,他的博客有进一步的深入探讨)?至少这是我发现的唯一一件事,即使没有TOP运算符,它似乎也几乎接近我所遇到的问题。

Answers:


9

带有位图筛选器的查询计划有时可能很难读取。从BOL有关分区流的文章(重点是我的):

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

此外,有关位图过滤器的文章也很有帮助:

分析包含位图筛选的执行计划时,重要的是要了解数据如何流经计划以及在何处应用筛选。位图过滤器和优化的位图是在哈希联接的构建输入(维度表)侧创建的;但是,实际过滤通常是在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;

这是您不应运行的查询:

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);

我上传了计划。看一下附近的操作员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以及派生表来强制联接最后执行,或者您甚至可以从查询中注释掉联接。希望这些建议足以使您入门。

关于问题中的连接项,极不可能与您的问题有关。该问题与行估计不佳无关。它与并行的竞争条件有关,竞争条件导致在后台的查询计划中要处理太多行。在这里,您的查询似乎没有做任何额外的工作。


6

此处的核心问题是对首次连接的结果的基数估计不佳。发生这种情况的原因可能很多,但最常见的是要么是过时的统计信息,要么是许多相关的联接谓词,优化器的默认模型假定这些谓词是独立的。

在后一种情况下,FIX:运行SQL Server 2008或SQL Server 2008 R2或SQL Server 2012中包含相关和谓词的查询时性能不佳可能与受支持的跟踪标志4137有关。跟踪标记4199以启用优化程序修复,和/或2301启用建模扩展。在匿名计划的基础上很难知道。

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

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

如上所述,所有这些都不能解决对首次加入的估算不佳的核心问题,因此我实际上只是出于利益考虑而提及它。

有关位图和哈希联接的进一步阅读:


0

在Twitter上回复了您。我查看了随附的XML,并看到了不平衡的并行性。1个线程几乎具有所有实际行,而其他大多数则没有。这尖叫着出现了不平衡的并行性。因此,我将研究键/联接值及其各自的统计信息和基数。

根据您的其他想法,我不确定是否可以应用“连接”项,因为您粘贴的计划在我看到的任何地方均不包含TOP。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.