Problema de estimativa de cardinalidade na junção interna

13

Estou lutando para entender por que a estimativa de linhas é tão terrivelmente errada, eis o meu caso:

Associação simples - usando o SQL Server 2016 sp2 (o mesmo problema no sp1), dbcompatiblity = 130.

select Amount_TransactionCurrency_id, CurrencyShareds.id 
from CurrencyShareds 
    INNER JOIN annexes ON Amount_TransactionCurrency_id = CurrencyShareds.Id 
option (QUERYTRACEON 3604, QUERYTRACEON 2363);

O SQL estima 1 linha, enquanto 107131 e escolhe fazer um loop aninhado ( link para planejar ). Depois que as estatísticas são atualizadas no CurrencyShareds, a estimativa é boa e uma junção de mesclagem é escolhida ( link para o novo plano ). Assim que apenas um registro é adicionado ao CurrencyShareds, as estatísticas se tornam "obsoletas" e o sql volta à estimativa incorreta.

Eu não me preocuparia tanto com essa consulta simples, mas isso é apenas parte de uma consulta maior e este é o início de um dominó ...

Por que adicionar uma linha à tabela de 100 registros causa esse dano? Ao examinar a saída do rastreamento de estimativa de cardinalidade, vejo esse aviso, ***WARNING: badly-formed histogram ***mas não consegui encontrar mais nada sobre esse tópico.

Aqui está a saída completa da estimativa de cardinalidade:

Begin selectivity computation
Input tree:

LogOp_Join

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

ScaOp_Comp x_cmpEq

ScaOp_Identifier QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id

ScaOp_Identifier QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id

Plan for computation:

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1 *** WARNING: badly-formed histogram ***

Selectivity: 4.59503e-018

Stats collection generated:

CStCollJoin(ID=3, CARD=1 x_jtInner)

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

End selectivity computation

Estimating distinct count in utility function

Input stats collection:

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

Columns to distinct on:QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id

Plan for computation:

CDVCPlanLeaf

0 Multi-Column Stats, 1 Single-Column Stats, 0 Guesses

Covering multi-col stats id: 7

Using ambient cardinality 107131 to combine distinct counts:

5

Combined distinct count: 5

Result of computation: 5

Estimating distinct count in utility function

Input stats collection:

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

Columns to distinct on:QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id

Plan for computation:

CDVCPlanUniqueKey

Result of computation: 100

E quando eu atualizo as estatísticas do CurrencyShareds, a parte com "histograma mal formado" é alterada e a cardinalidade é calculada corretamente

Plan for computation:

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1

Selectivity: 0.01

Stats collection generated:

CStCollJoin(ID=3, CARD=107131 x_jtInner)

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

End selectivity computation

E informações de estatísticas para este "[CurrencyShareds] .Id a partir de estatísticas com o ID 1" com aviso sobre o histograma, o que parece bom para mim ...

Name                                                                                                                             Updated              Rows                 Rows Sampled         Steps  Density       Average key length String Index Filter Expression                                                                                                                                                                                                                                                Unfiltered Rows      Persisted Sample Percent
-------------------------------------------------------------------------------------------------------------------------------- -------------------- -------------------- -------------------- ------ ------------- ------------------ ------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------- ------------------------
PK_CurrencyShareds_Id                                                                                                            May 23 2018 10:43PM  98                   98                   75     1             8                  NO           NULL                                                                                                                                                                                                                                                             98                   0

(1 row affected)

All density   Average Length Columns
------------- -------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0,01020408    8              Id

(1 row affected)

RANGE_HI_KEY         RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
-------------------- ------------- ------------- -------------------- --------------
119762190797406464   0             1             0                    1
119762190797406466   1             1             1                    1
119762190797406468   1             1             1                    1
119762190797406470   1             1             1                    1
119762190797406472   1             1             1                    1
119762190797406474   1             1             1                    1
119762190797406476   1             1             1                    1
119762190797406478   1             1             1                    1
119762190797406480   1             1             1                    1
119762190797406482   1             1             1                    1
119762190797406484   1             1             1                    1
119762190797406486   1             1             1                    1
119762190797406488   1             1             1                    1
119762190797406490   1             1             1                    1
119762190797406492   1             1             1                    1
119762190797406494   1             1             1                    1
119762190797406496   1             1             1                    1
119762190797406498   1             1             1                    1
119762190797406500   1             1             1                    1
119762190797406502   1             1             1                    1
119762190797406504   1             1             1                    1
119762190797406506   1             1             1                    1
119762190797406507   0             1             0                    1
478531702587687680   0             1             0                    1
478531702591881728   0             1             0                    1
478531702591881729   0             1             0                    1
478531702591881984   0             1             0                    1
478531702591881985   0             1             0                    1
478531702596076032   0             1             0                    1
478531702596076033   0             1             0                    1
478531702596076288   0             1             0                    1
478531702600270336   0             1             0                    1
478531702600270592   0             1             0                    1
478532235583062528   0             1             0                    1
478532235583062784   0             1             0                    1
478532235587256832   0             1             0                    1
530792464911467264   0             1             0                    1
530792464924049920   0             1             0                    1
530792464924050176   0             1             0                    1
530792464928244224   0             1             0                    1
530792464928244480   0             1             0                    1
530792464932438528   0             1             0                    1
530792464932438784   0             1             0                    1
530792464936632832   0             1             0                    1
530792464936632833   0             1             0                    1
530792464936633088   0             1             0                    1
530792464940827136   0             1             0                    1
530792464940827392   0             1             0                    1
530792464949216000   2             1             2                    1
530792464953410048   0             1             0                    1
530792464953410304   0             1             0                    1
530792464957604352   0             1             0                    1
530792464957604353   0             1             0                    1
530792464957604608   0             1             0                    1
530792464961798656   0             1             0                    1
530792464961798912   0             1             0                    1
530792464965992960   0             1             0                    1
530792464965993216   0             1             0                    1
530792464965993217   0             1             0                    1
530792464970187264   0             1             0                    1
530792464970187265   0             1             0                    1
530792464970187520   0             1             0                    1
530792464974381568   0             1             0                    1
530792464974381824   0             1             0                    1
530792464974381825   0             1             0                    1
530792464978575872   0             1             0                    1
530792464978575873   0             1             0                    1
530792464978576128   0             1             0                    1
867420708903354880   0             1             0                    1
867420708903355136   0             1             0                    1
867420708903355137   0             1             0                    1
960876568220042240   0             1             0                    1
976385263448130048   0             1             0                    1
977302121709864192   0             1             0                    1
977955748426318592   0             1             0                    1

e informações para o segundo índice:

Name                                                                                                                             Updated              Rows                 Rows Sampled         Steps  Density       Average key length String Index Filter Expression                                                                                                                                                                                                                                                Unfiltered Rows      Persisted Sample Percent
-------------------------------------------------------------------------------------------------------------------------------- -------------------- -------------------- -------------------- ------ ------------- ------------------ ------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------- ------------------------
IX_FK_Amount_TransactionCurrency                                                                                                 May 21 2018  3:29PM  107204               107204               5      0             16                 NO           NULL                                                                                                                                                                                                                                                             107204               0

(1 row affected)

All density   Average Length Columns
------------- -------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0,2           8              Amount_TransactionCurrency_id
9,32801E-06   16             Amount_TransactionCurrency_id, Id

(2 rows affected)

RANGE_HI_KEY         RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
-------------------- ------------- ------------- -------------------- --------------
119762190797406475   0             160           0                    1
119762190797406478   0             867           0                    1
119762190797406481   0             106           0                    1
119762190797406494   0             105742        0                    1
119762190797406496   0             329           0                    1
LeMaciek
fonte

Respostas:

10

Com base nos seus histogramas, pude reproduzir novamente o problema em 2017 CU6. Eu não diria que você está fazendo algo errado. Em vez disso, algo está errado com a estimativa de cardinalidade. Aqui está o que eu recebo antes de inserir uma linha:

insira a descrição da imagem aqui

A estimativa final da cardinalidade cai bastante após a inserção de uma linha:

insira a descrição da imagem aqui

Você tem uma reprodução muito simples aqui, então meu conselho é registrar comentários sobre o produto ou abrir um tíquete de suporte na Microsoft. Consegui encontrar algumas soluções alternativas que funcionavam nos seus dados de amostra e uma das que poderia ser aceitável para você.

  1. Solte o índice exclusivo CurrencyShareds.Id. Não consigo fazer o repro funcionar sem um índice exclusivo. A tabela é pequena, então talvez você possa sobreviver sem o índice. Obviamente, você pode ter boas razões para mantê-lo.
  2. Materialize os resultados da junção em uma tabela temporária. Com base na sua pergunta, é importante obter uma estimativa razoável nesta etapa para que a consulta maior tenha um bom desempenho. Uma tabela temporária é uma maneira de fazer isso acontecer.
  3. Use o CE legado. Não consigo reproduzir o problema com ele. Obviamente, isso pode ter consequências negativas no restante da sua consulta.
  4. Engane o otimizador de consulta com código tolo. Por exemplo, nos meus testes, a seguinte reescrita funciona muito bem:

.

select Amount_TransactionCurrency_id, CurrencyShareds.id
from CurrencyShareds 
INNER JOIN annexes
ON Amount_TransactionCurrency_id % 9223372036854775809 = CurrencyShareds.Id % 9223372036854775809

Eu suspeito que isso funcione porque o CE parece usar a densidade em vez do histograma. Outras regravações semelhantes podem ter o mesmo efeito. Não há garantia de que o tipo de consulta continue a funcionar bem no futuro. É por isso que você deve entrar em contato com a Microsoft para aumentar as chances de que um dia uma correção do seu problema consiga entrar no produto lançado.

Joe Obbish
fonte
8

Ok, espero entender agora - então esse é o nosso caso

Dado

  1. Uma tabela de referência (CurrencyShareds) com ~ 100 linhas, mas os IDs são grandes e mín. Os valores máximos diferem muito - mín: 119.762.190.797.406.464 vs max: 977.955.748.426.318
  2. Uma tabela (anexos) que possui FK simples para CurrencyShared, mas apenas algumas moedas são usadas - você pode ver que o histograma para IX_FK_Amount_TransactionCurrency lista 5 IDs - e o que é importante apenas esses IDs "baixos", pois outros não são usados.

Quando todas as estatísticas estiverem atualizadas,

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1

Selectivity: 0.01

Então, a seletividade calculada para a junção é boa, pois 100 * 107,131 * 0,01 = 107,131

Quando as estatísticas dos compartilhamentos de moedas não estiverem atualizadas,

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1 *** WARNING: badly-formed histogram ***

Selectivity: 4.59503e-018

A seletividade cai drasticamente e, portanto, o número estimado de linhas da junção é 1.

Quando o histograma muda

Depois de adicionar uma única linha aos anexos que refiram CurrencyShared com o ID alto, o resultado é o histograma para IX_FK_Amount_TransactionCurrency alterado para

RANGE_HI_KEY         RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
-------------------- ------------- ------------- -------------------- --------------
119762190797406475   0             173           0                    1
119762190797406478   0             868           0                    1
119762190797406481   0             107           0                    1
119762190797406494   0             105745        0                    1
119762190797406496   0             330           0                    1
119762190797406618   0             1             0                    1
119762190797406628   0             1             0                    1
977955748426318623   0             1             0                    1

Com esse histograma, o problema desaparece, agora a adição de uma nova linha aos compartilhamentos de moedas não causa uma queda drástica na estimativa de cardinalidade.

Por que é que?

Eu suspeito que é assim que o algoritmo de estimativa de histograma grosso funciona no sql2014 +, e estou baseando meu palpite neste ótimo post https://www.sqlshack.com/join-estimation-internals/

A estimativa grosseira do histograma é um novo algoritmo e menos documentado, mesmo em termos de conceitos gerais. Sabe-se que, em vez de alinhar os histogramas passo a passo, os alinha apenas com os limites mínimo e máximo do histograma. Esse método apresenta potencialmente menos erros de CE (nem sempre, no entanto, porque lembramos que este é apenas um modelo).

Apenas para esclarecer tudo - por que temos identificações tão estranhas nos compartilhamentos de moedas?

É bem simples - nossos IDs são globalmente exclusivos e se baseiam em parte no carimbo de data / hora (implementação baseada em floco de neve ). As moedas mais comuns foram adicionadas no início do aplicativo há vários anos e apenas essas poucas são realmente usadas na produção, por isso, no histograma, existem apenas aquelas com ID "baixo".

O problema surgiu em nossos ambientes de teste, onde alguns testes automatizados começaram a adicionar moedas de teste, fazendo com que algumas consultas fossem executadas por mais tempo ou atingiram o tempo limite ...

Como resolver o problema?

Atualizaremos estatísticas para essas tabelas de referência (podemos ter um problema semelhante com outras tabelas de dados de referência semelhantes) com mais frequência - essas tabelas são pequenas, portanto, atualizar estatísticas não é um problema

Lições aprendidas

  • Estatísticas atualizadas são importantes !!!
  • coluna de identidade antiga simples não causaria esses problemas :)
LeMaciek
fonte
Em relação ao alinhamento aproximado: sqlperformance.com/2018/11/sql-optimizer/…
Paul White 9