Stima dell'ardinalità di predicati di range parzialmente coprenti


13

Al momento sto cercando di capire come SQL Server valuta la cardinalità dei predicati di intervallo che coprono parzialmente il passaggio dell'istogramma.

Su Internet, alla stima della cardinalità-per-e-per-intra-step-valore-statistica ho incontrato una domanda simile e Paul White ha dato una risposta piuttosto interessante ad essa.

Secondo la risposta di Paul, le formule per stimare la cardinalità per i predicati> = e> (in questo caso, sono interessato solo al modello dello stimatore della cardinalità di almeno 120) sono le seguenti:

Per>:

Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1)))

Per> =:

Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))

Ho testato l'applicazione di queste formule sulla tabella [Production]. [TransactionHistory] del database AdventureWorks2014 in base al predicato di intervallo utilizzando la colonna TransactionDate e l'intervallo di dati tra '20140614' e '20140618'.

Le statistiche per il passaggio dell'istogramma di questo intervallo sono le seguenti:

Istogramma

Secondo la formula, ho calcolato la cardinalità per la seguente query:

SELECT COUNT(1)
FROM [AdventureWorks2014].[Production].[TransactionHistory]
WHERE [TransactionDate] BETWEEN '20140615 00:00:00.000' AND '20140616 00:00:00.000'

Il calcolo è stato eseguito utilizzando il seguente codice:

  DECLARE @predStart DATETIME =  '20140615 00:00:00.000'
  DECLARE @predEnd DATETIME = '20140616 00:00:00.000'

  DECLARE @stepStart DATETIME = '20140614 00:00:00.000'
  DECLARE @stepEnd DATETIME = '20140618 00:00:00.000'

  DECLARE @predRange FLOAT = DATEDIFF(ms, @predStart, @predEnd)
  DECLARE @stepRange FLOAT = DATEDIFF(ms, @stepStart, @stepEnd)

  DECLARE @F FLOAT = @predRange / @stepRange;

  DECLARE @avg_range_rows FLOAT = 100.3333
  DECLARE @distinct_range_rows INT = 3
  DECLARE @EQ_ROWS INT = 0

  SELECT @F AS 'F'

  --for new cardinality estimator

  SELECT @EQ_ROWS + @avg_range_rows * (@F * (@distinct_range_rows - 1) + 1) AS [new_card]

Dopo il calcolo, ho ottenuto i seguenti risultati:

inserisci qui la descrizione dell'immagine

Secondo la formula, risultava 150,5, ma l'ottimizzatore stima il predicato in 225,75 righe e se si modifica il bordo superiore del predicato in "20140617", l'ottimizzatore valuterà già 250.833 righe, mentre utilizzando la formula si ottiene solo 200.6666 righe.

Per favore dimmi, come valuta lo stimatore della cardinalità in questo caso, forse ho fatto un errore da qualche parte nella mia comprensione delle formule citate?


SQL Server 2014 12.0.5 SP2
Павел Ковалёв

Risposte:


12

SQL Server utilizza calcoli diversi in diverse situazioni. Il tuo esempio è diverso dalle domande e risposte collegate perché il tuo intervallo è interamente contenuto in un passaggio; non attraversa un limite di gradino. È anche un intervallo con due estremità anziché una. Scrivere BETWEENequivale a scrivere due predicati separati con >=e <=.

Intervallo con due limiti, all'interno di un singolo passaggio

La formula viene modificata per eseguire l'interpolazione lineare all'interno della fase per il numero di valori distinti previsti e riflettere che due endpoint di intervallo sono ora specificati (e si presume esistano all'interno della fase dell'istogramma) anziché uno.

Utilizzando i passaggi dell'istogramma indicati nella domanda:

domanda passaggi dell'istogramma

Per la query con BETWEEN '20140615' AND '20140616', il calcolo è:

DECLARE
    @Q1 float = CONVERT(float, CONVERT(datetime, '2014-06-15')),
    @Q2 float = CONVERT(float, CONVERT(datetime, '2014-06-16')),
    @K1 float = CONVERT(float, CONVERT(datetime, '2014-06-14')),
    @K2 float = CONVERT(float, CONVERT(datetime, '2014-06-18')),
    @RANGE_ROWS float = 301,
    @DISTINCT_RANGE_ROWS float = 3;

DECLARE
    @S1 float = (@Q1 - @K1) / (@K2 - @K1),
    @S2 float = (@Q2 - @K1) / (@K2 - @K1);

DECLARE
    @F float = @S2 - @S1;

DECLARE
    @AVG_RANGE_ROWS float = @RANGE_ROWS / @DISTINCT_RANGE_ROWS;

SELECT
    @AVG_RANGE_ROWS * ((@F * (@DISTINCT_RANGE_ROWS - 2)) + 2);

... dando 225.75 . La modifica @Q2da '20140616'a '20140617'dà un risultato di 250,833 .

Entrambi i risultati corrispondono a quelli indicati nella domanda.

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.