Configuração
Estou tendo problemas para entender uma estimativa de cardinalidade. Aqui está a minha configuração de teste:
- a versão 2010 do banco de dados Stack Overflow
- SQL Server 2017 CU15 + GDR (KB4505225) - 14.0.3192.2
- o novo CE (nível de compatibilidade 140)
Eu tenho este proc:
USE StackOverflow2010;
GO
CREATE OR ALTER PROCEDURE #sp_PostsByCommentCount
@CommentCount int
AS
BEGIN
SELECT *
FROM dbo.Posts p
WHERE
p.CommentCount = @CommentCount
OPTION (RECOMPILE);
END;
GO
Não há índices ou estatísticas não clusterizados na dbo.Posts
tabela (existe um índice clusterizado Id
).
Ao solicitar um plano estimado para isso, as "linhas estimadas" dbo.Posts
são 1.934,99:
EXEC #sp_PostsByCommentCount @CommentCount = 51;
O seguinte objeto estatístico foi criado automaticamente quando solicitei o plano estimado:
DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);
Os destaques são:
- As estatísticas têm uma taxa de amostragem bastante baixa de 1,81% (67.796 / 3.744.192)
- Apenas 31 etapas do histograma foram usadas
- O valor "Toda a densidade" é
0.03030303
(33 valores distintos foram amostrados) - O último
RANGE_HI_KEY
no histograma é 50, comEQ_ROWS
1
Questão
Passar qualquer valor acima de 50 (até 2.147.483.647) incluindo os resultados na estimativa de linha de 1.934,99. Qual cálculo ou valor é usado para produzir essa estimativa? O estimador de cardinalidade herdado produz uma estimativa de 1 linha, a propósito.
O que eu tentei
Aqui estão algumas teorias que eu tinha, coisas que tentei ou informações adicionais que consegui descobrir ao analisar isso.
Vetor de densidade
Inicialmente, pensei que seria o vetor de densidade, o mesmo que se eu tivesse usado OPTION (OPTIMIZE FOR UNKNOWN)
. Mas o vetor de densidade para esse objeto de estatísticas é 3.744.192 * 0,03030303 = 113.460, então não é isso.
Eventos estendidos
Tentei executar uma sessão de evento estendido que coletou o query_optimizer_estimate_cardinality
evento (sobre o qual aprendi na postagem do blog de Paul White sobre Cardinality Estimation: Combining Density Statistics ) e recebi esses tipos de petiscos interessantes:
<CalculatorList>
<FilterCalculator CalculatorName="CSelCalcColumnInInterval" Selectivity="-1.000"
CalculatorFailed="true" TableName="[p]" ColumnName="CommentCount" />
<FilterCalculator CalculatorName="CSelCalcAscendingKeyFilter" Selectivity="0.001"
TableName="[p]" ColumnName="CommentCount" UseAverageFrequency="true"
StatId="4" />
</CalculatorList>
Parece que a CSelCalcAscendingKeyFilter
calculadora foi usada (a outra diz que falhou, o que quer que isso signifique). Esta coluna não é uma chave, é única ou necessariamente é ascendente, mas é o que for.
Ao pesquisar no Google, esse termo me levou a algumas postagens no blog:
- Joe Sack - a calculadora CSelCalcAscendingKeyFilter ,
- Itzik Ben-Gan - Procure e você deverá escanear a Parte II: Teclas Ascendentes
Esses posts indicam que o novo CE baseia essas estimativas fora do histograma em uma combinação do vetor de densidade e do contador de modificações do stat. Infelizmente, eu já descartei o vetor de densidade (eu acho ?!), e o contador de modificações é zero (de sys.dm_db_stats_properties
qualquer maneira).
Sinalizadores de rastreamento
Forrest sugeriu que eu ative o TF 2363 para obter mais informações sobre o processo de estimativa. Eu acho que a coisa mais relevante nessa saída é esta:
Plan for computation:
CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)
Selectivity: 0.000516798
Esta é uma descoberta (obrigado, Forrest!): Esse 0.000516798
número (que parece ter sido arredondado sem ajuda no Selectivity="0.001"
atributo XE acima) multiplicado pelo número de linhas da tabela é a estimativa que eu estou procurando (1.934,99).
Provavelmente estou perdendo algo óbvio, mas não consegui fazer engenharia reversa de como esse valor de seletividade é produzido dentro da CSelCalcAscendingKeyFilter
calculadora.