Temos uma consulta em um SQL Server 2016 SP2 CU12 Enterprise em que o Query Optimizer estima que apenas 1 linha sairia do operador Nested Loops Join , na realidade 108501 linhas voltaram. Isso fez com que o Sort
operador vazasse para o TempDB.
As estimativas na entrada interna (busca de índice) e externa (busca de índice) da junção de loops aninhados estão corretas.
Adicionei os sinalizadores de rastreamento 2363 (Cálculo de Seletividade) e 3604 (redirecione a saída para a janela de mensagens) e aqui descobri que havia um histograma mal formado:
Plan for computation: CSelCalcExpressionComparedToExpression( QCOL: [Object1].Column1 x_cmpEq QCOL: [Object3].Column18 ) Loaded histogram for column QCOL: [Object1].Column1 from stats with id 1 *** WARNING: badly-formed histogram *** Loaded histogram for column QCOL: [Object3].Column18 from stats with id 9 Selectivity: 1.07973e-009 Stats collection generated: CStCollJoin(ID=4, CARD=1 x_jtLeftSemi) CStCollBaseTable(ID=1, CARD=5.01133e+007 TBL: Schema1.Table2 AS TBL: AA) CStCollFilter(ID=3, CARD=108210) CStCollBaseTable(ID=2, CARD=2.00511e+006 TBL: Schema1.Table1 AS TBL: A) End selectivity computation
Acima é apenas uma parte da saída, o texto completo pode ser encontrado aqui
Quando atualizei o histograma mal formado com fullscan, as estimativas estão corretas (sem fullscan, esse problema não é resolvido).
Mas assim que um registro é inserido na tabela, o histograma está mal formado novamente.
O plano de consulta (com histograma mal formado) pode ser encontrado aqui e aqui você pode encontrar o plano de consulta após a atualização das estatísticas.
Nenhuma correção do otimizador de consulta está habilitada. Quando habilito o estimador de cardinalidade original para esta consulta, usando o sinalizador de rastreamento 9481, estou obtendo o mesmo plano de consulta após as estatísticas de atualização.
O que pode causar o histograma mal formado?
Existe uma maneira de resolver este problema?
Tentei a PERSIST_SAMPLE_PERCENT
opção mas não fez diferença, o histograma também fica mal formado.
Isso é um bug, claro. Ocorre quando o SQL Server dimensiona o histograma inexato e encontra uma coluna exclusiva com aparentemente mais de um valor por chave. Isso foi parcialmente resolvido para o SQL Server 2016, mas parece-me que a correção completa está presente apenas no SQL Server 2017 (testei no CU21).
Use
FULLSCAN
estatísticas, o CE original, atualize para o SQL Server 2017 ou aguarde a portabilidade da correção completa.Demonstração
Usando meu script de criação de tabela padrão do Numbers:
Atualize as estatísticas a serem amostradas:
Consulta trivial (solicitar apenas um plano estimado):
A saída de rastreamento inclui:
Validado no Microsoft SQL Server 2016 (SP2-CU14).
O histograma estatístico obtido via:
tem entradas como:
no SQL Server 2017 o histograma é:
Observe que as
EQ_ROWS
etapas são pré-escalonadas em vez de depender do CE para fazê-lo.