Stima della cardinalità al di fuori dell'istogramma


14

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.Poststabella (è attivo un indice cluster Id).

Quando si richiede un piano stimato per questo, le "righe stimate" in uscita dbo.Postssono 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]);

screenshot dell'output delle statistiche in SSMS

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_KEYnell'istogramma è 50, con EQ_ROWS1

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_cardinalityevento (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 CSelCalcAscendingKeyFilterstata 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:

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_propertiescomunque).

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.000516798numero (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 CSelCalcAscendingKeyFiltercalcolatrice.

Risposte:


13

Sulla base dei miei test, la stima della cardinalità fuori limite è semplicemente la radice quadrata del conteggio delle righe, delimitata di seguito dal numero di righe aggiunte dall'ultimo aggiornamento delle statistiche e delimitata sopra dalle righe medie per valore.

Nel tuo caso, 1.934,99 = SQRT (3744192)

Configurazione di prova di seguito:

--setup
USE TestDB
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS OFF
GO

DROP TABLE IF EXISTS dbo.Hist

CREATE TABLE dbo.Hist (
ID int identity primary key,
Num int
)

INSERT dbo.Hist
SELECT TOP 300
(ROW_NUMBER() OVER(ORDER BY(SELECT 1/0)))%3
FROM master..spt_values a
CROSS JOIN master..spt_values b
--Get estimated plan
--don't forget to run right after setup to auto-create stats
SELECT *
FROM dbo.Hist
WHERE Num = 1000
--gradually add rows, then rerun estimate above
INSERT dbo.Hist
SELECT TOP 100
-1
FROM master..spt_values a
--I sure hope you weren't testing this in prod (cleanup)
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS ON
GO

Stime sorprendentemente uniformi delle righe sono state generate da questo approccio: 20 a 400 righe totali, 30 a 900, 40 a 1600, ecc.

Oltre 10000, tuttavia, la stima delle righe raggiunge il massimo a 100, ovvero il numero di righe per valore nelle statistiche esistenti. L'aggiunta di solo 10 righe imposterà la stima su 10, poiché sqrt (300)> 10.

Quindi le stime potrebbero essere espresse usando questa formula:

Estimate = MIN(SQRT(AC), MIN(AR, MC))

Si noti che se vengono campionate le statistiche, MC non viene considerato. Quindi la formula diventa:

Estimate = MIN(SQRT(AC), AR))

Dove

  • MC è il "conteggio delle modifiche" (numero di modifiche da quando sono state create le statistiche)
  • AC è la "cardinalità corretta" (numero di righe dalle statistiche più MC),
  • AR è la media delle righe per valore (numero di righe dalle statistiche diviso per valori distinti nella colonna)

Le formule per queste stime e altri dettagli sulla calcolatrice sono disponibili in questo post del blog: Analisi delle stime dal calcolatore CSelCalcAscendingKeyFilter

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.