Impostare
Ho dei problemi a capire una stima della cardinalità. Ecco la mia configurazione di prova:
- la versione 2010 del database Stack Overflow
- SQL Server 2017 CU15 + GDR (KB4505225) - 14.0.3192.2
- il nuovo CE (livello di compatibilità 140)
Ho questo 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
Non ci sono indici o statistiche non cluster sulla dbo.Posts
tabella (è attivo un indice cluster Id
).
Quando si richiede un piano stimato per questo, le "righe stimate" in uscita dbo.Posts
sono 1.934,99:
EXEC #sp_PostsByCommentCount @CommentCount = 51;
Il seguente oggetto statistico è stato creato automaticamente quando ho chiesto il piano stimato:
DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);
I punti salienti di ciò sono:
- Le statistiche hanno una frequenza di campionamento piuttosto bassa dell'1,81% (67.796 / 3.744.192)
- Sono stati utilizzati solo 31 passaggi dell'istogramma
- Il valore "Tutta la densità" è
0.03030303
(sono stati campionati 33 valori distinti) - L'ultimo
RANGE_HI_KEY
nell'istogramma è 50, conEQ_ROWS
1
Domanda
Il passaggio di qualsiasi valore superiore a 50 (fino a 2.147.483.647 inclusi) comporta la stima di 1.934,99 righe. Quale calcolo o valore viene utilizzato per produrre questa stima? A proposito, lo stimatore della cardinalità legacy produce una stima di 1 riga.
Quello che ho provato
Ecco alcune teorie che ho avuto, cose che ho provato o informazioni aggiuntive che sono stato in grado di approfondire mentre guardavo in questo.
Densità vettoriale
Inizialmente pensavo che sarebbe stato il vettore di densità, lo stesso che se avessi usato OPTION (OPTIMIZE FOR UNKNOWN)
. Ma il vettore di densità per questo oggetto stats è 3.744.192 * 0,03030303 = 113.460, quindi non è così.
Eventi estesi
Ho provato a organizzare una sessione di eventi estesi che ha raccolto l' query_optimizer_estimate_cardinality
evento (di cui ho appreso dal post sul blog di Paul White Stima della cardinalità: Combinare le statistiche sulla densità ) e ho ottenuto questo tipo di notizie interessanti:
<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>
Quindi sembra che sia CSelCalcAscendingKeyFilter
stata utilizzata la calcolatrice (l'altra dice che non è riuscita, qualunque cosa significhi). Questa colonna non è una chiave, o unica, o necessariamente crescente, ma qualunque cosa.
Fare alcuni googling di quel termine mi ha portato ad alcuni post sul blog:
- Joe Sack - The CSelCalcAscendingKeyFilter Calculator ,
- Itzik Ben-Gan - Seek and You Shall Scan Part II: Ascending Keys
Questi post indicano che il nuovo CE basa queste stime al di fuori dell'istogramma su una combinazione del vettore di densità e del contatore di modifiche delle statistiche. Sfortunatamente, ho già escluso il vettore di densità (penso ?!) e il contatore delle modifiche è zero ( sys.dm_db_stats_properties
comunque).
Bandiere di traccia
Forrest mi ha suggerito di attivare TF 2363 per ottenere ulteriori informazioni sul processo di stima. Penso che la cosa più rilevante da quell'output sia questa:
Plan for computation:
CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)
Selectivity: 0.000516798
Questa è una svolta (grazie, Forrest!): Quel 0.000516798
numero (che sembra essere stato inutilmente arrotondato nell'attributo XE Selectivity="0.001"
sopra) moltiplicato per il numero delle righe nella tabella è la stima che stavo cercando (1.934,99).
Probabilmente mi manca qualcosa di ovvio, ma non sono stato in grado di decodificare il modo in cui quel valore di selettività viene prodotto all'interno della CSelCalcAscendingKeyFilter
calcolatrice.