Por que o operador Parallelism (Repartition Streams) reduziria as estimativas de linha para 1?

12

Estou usando o SQL Server 2012 Enterprise. Encontrei um plano SQL que exibe algum comportamento que não acho totalmente intuitivo. Após uma operação pesada de Varredura de Índice Paralela, ocorre uma operação Paralelismo (Fluxos de Repartição), mas está matando as estimativas de linha retornadas pela Varredura de Índice (Object10.Index2), reduzindo a estimativa para 1. Fiz algumas pesquisas, mas não encontrei nada que explique esse comportamento. A consulta é bastante simples, embora cada uma das tabelas contenha registros na casa dos milhões. Isso faz parte de um processo de carregamento DWH e esse conjunto de dados intermediários é abordado algumas vezes, mas a pergunta que tenho está relacionada às estimativas de linha em particular. Alguém pode explicar por que as estimativas de linha precisas vão para 1 no operador Parallelism (Repartition Strems)? Além disso,

Publiquei o plano completo para Colar o plano .

Aqui está a operação em questão:

insira a descrição da imagem aqui

Incluindo a Árvore do Plano, caso isso adicione mais contexto:

insira a descrição da imagem aqui

Poderia me deparar com alguma variação deste item do Connect arquivada por Paul White (uma explicação mais aprofundada em seu blog aqui )? Pelo menos, é a única coisa que descobri que parece estar remotamente próxima do que estou encontrando, mesmo que não haja um operador TOP em jogo.

John Eisbrener
fonte

Respostas:

9

Às vezes, os planos de consulta com filtros de bitmap podem ser difíceis de ler. Do artigo BOL para fluxos de repartição (ênfase minha):

O operador Repartition Streams consome vários fluxos e produz vários fluxos de registros. O conteúdo e o formato do registro não são alterados. Se o otimizador de consulta usar um filtro de bitmap, o número de linhas no fluxo de saída será reduzido.

Além disso, um artigo sobre filtros de bitmap também é útil:

Ao analisar um plano de execução contendo filtragem de bitmap, é importante entender como os dados fluem pelo plano e onde a filtragem é aplicada. O filtro de bitmap e o bitmap otimizado são criados no lado da entrada de construção (a tabela de dimensões) de uma junção de hash; no entanto, a filtragem real geralmente é feita no operador Parallelism, que está no lado de entrada do probe (a tabela de fatos) da junção de hash. No entanto, quando o filtro de bitmap é baseado em uma coluna inteira, o filtro pode ser aplicado diretamente à tabela inicial ou à operação de verificação de índice, em vez do operador Paralelismo. Essa técnica é chamada de otimização em linha.

Acredito que é isso que você está observando com sua consulta. É possível criar uma demonstração relativamente simples para mostrar um operador de fluxos de repartição reduzindo uma estimativa de cardinalidade, mesmo quando o operador de bitmap está IN_ROWna tabela de fatos. Preparação de dados:

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;

Aqui está uma consulta que você não deve executar:

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

Eu enviei o plano . Dê uma olhada no operador próximo a inner_tbl_2:

reparticionar linhas perdidas

Você também pode encontrar o segundo teste em Hash Joins on Nullable Columns de Paul White útil.

Existem algumas inconsistências em como a redução de linha é aplicada. Eu só conseguia vê-lo em um plano com pelo menos três mesas. No entanto, a redução nas linhas esperadas parece razoável com a distribuição de dados correta. Suponha que a coluna unida na tabela de fatos tenha muitos valores repetidos que não estão presentes na tabela de dimensões. Um filtro de bitmap pode eliminar essas linhas antes que elas atinjam a associação. Para sua consulta, a estimativa é reduzida a 1. Como a distribuição das linhas entre a função hash fornece uma boa dica:

distribuição de linha

Com base nisso, suspeito que você tenha muitos valores repetidos para a Object1.Column21coluna. Se as colunas repetidas não estiverem no histograma de estatísticas para o Object4.Column19SQL Server, a estimativa de cardinalidade pode estar errada.

Eu acho que você deve se preocupar, pois pode ser possível melhorar o desempenho da consulta. Obviamente, se a consulta atender ao tempo de resposta ou aos requisitos do SLA, poderá não valer mais investigação. No entanto, se você deseja investigar mais, há algumas coisas que você pode fazer (além de atualizar estatísticas) para ter uma idéia de se o otimizador de consulta escolheria um plano melhor se tivesse informações melhores. Você pode colocar os resultados da junção entre Database1.Schema1.Object10e Database1.Schema1.Object11em uma tabela temporária e ver se continua obtendo junções de loop aninhadas. Você pode alterar essa associação para uma LEFT OUTER JOINpara que o otimizador de consulta não reduza o número de linhas nessa etapa. Você pode adicionar uma MAXDOP 1dica à sua consulta para ver o que acontece. Você poderia usarTOPjunto com uma tabela derivada para forçar a junção a ir por último, ou você pode até comentar a junção na consulta. Espero que essas sugestões sejam suficientes para você começar.

Em relação ao item de conexão na pergunta, é extremamente improvável que esteja relacionado à sua pergunta. Esse problema não tem a ver com estimativas ruins de linha. Tem a ver com uma condição de corrida em paralelismo que faz com que muitas linhas sejam processadas no plano de consulta nos bastidores. Aqui, parece que sua consulta não está fazendo nenhum trabalho extra.

Joe Obbish
fonte
6

O principal problema aqui é uma fraca estimativa de cardinalidade para o resultado da primeira junção. Isso pode surgir por vários motivos, mas na maioria das vezes são estatísticas desatualizadas ou vários predicados de junção correlacionados, que o modelo padrão do otimizador supõe serem independentes.

No último caso, CORRECÇÃO: Desempenho ruim quando você executa uma consulta que contém predicados AND correlacionados no SQL Server 2008 ou no SQL Server 2008 R2 ou no SQL Server 2012 pode ser relevante usando o sinalizador de rastreamento suportado 4137. Você também pode tentar a consulta com sinalizador de rastreamento 4199 para ativar correções do otimizador e / ou 2301 para ativar extensões de modelagem. É difícil saber com base em um plano anônimo.

A presença do bitmap não afeta diretamente a estimativa de cardinalidade da junção, mas torna seu efeito visível mais cedo aplicando a redução antecipada de semijoin. Sem o bitmap, a estimativa de cardinalidade para a primeira junção seria a mesma e o restante do plano ainda seria otimizado de acordo.

Se você estiver curioso, em um sistema de teste, poderá desativar os bitmaps da consulta com o sinalizador de rastreamento 7498. Você também pode desativar os bitmaps otimizados (considerados pelo otimizador e afetando as estimativas de cardinalidade), substituindo-os por bitmaps pós-otimização (não considerados pelo otimizador, sem efeito na cardinalidade) com uma combinação dos sinalizadores de rastreamento 7497 e 7498. Nenhum deles é documentado ou suportado para uso em um sistema de produção, mas eles produzem planos que o otimizador poderia considerar normalmente e, portanto, pode ser forçado com um guia de plano.

Nada disso resolverá o problema central da estimativa ruim para a primeira associação, como mencionado acima, por isso estou apenas mencionando isso por uma questão de interesses.

Leitura adicional sobre bitmaps e junções de hash:

Paul White 9
fonte
0

respondeu a você no Twitter. Eu olhei para o XML anexado e vi um paralelismo desequilibrado. 1 thread possui quase todas as linhas reais, enquanto a maioria dos outros não. Isso grita paralelismo desequilibrado está ocorrendo. Portanto, eu examinaria o valor da chave / junção e suas respectivas estatísticas e cardinalidade.

De acordo com sua outra ideia, não tenho tanta certeza de que o item Conectar se aplique, pois seu plano colado não contém TOP em qualquer lugar que eu tenha visto.

SQLBek
fonte