À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_ROW
na 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
:
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:
Com base nisso, suspeito que você tenha muitos valores repetidos para a Object1.Column21
coluna. Se as colunas repetidas não estiverem no histograma de estatísticas para o Object4.Column19
SQL 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.Object10
e Database1.Schema1.Object11
em uma tabela temporária e ver se continua obtendo junções de loop aninhadas. Você pode alterar essa associação para uma LEFT OUTER JOIN
para que o otimizador de consulta não reduza o número de linhas nessa etapa. Você pode adicionar uma MAXDOP 1
dica à sua consulta para ver o que acontece. Você poderia usarTOP
junto 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.