Сardinality-Schätzung von teilweise abdeckenden Range-Prädikaten


13

Im Moment versuche ich herauszufinden, wie SQL Server die Kardinalität von Bereichsprädikaten bewertet, die den Histogrammschritt teilweise abdecken.

Im Internet stieß ich bei der Schätzung der Kardinalität für und für den Wert der Intra-Step-Statistik auf eine ähnliche Frage, und Paul White gab eine ziemlich interessante Antwort darauf.

Nach Pauls Antwort lauten die Formeln zur Schätzung der Kardinalität für die Prädikate> = und> (in diesem Fall interessiert mich nur das Kardinalitätsschätzermodell von mindestens 120):

Für>:

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

Für> =:

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

Ich habe die Anwendung dieser Formeln in der Tabelle [Production]. [TransactionHistory] der AdventureWorks2014- Datenbank getestet, basierend auf dem Bereichsprädikat unter Verwendung der TransactionDate- Spalte und des datetime-Bereichs zwischen '20140614' und '20140618'.

Die Statistiken für den Histogrammschritt dieses Bereichs lauten wie folgt:

Histogramm

Gemäß der Formel habe ich die Kardinalität für die folgende Abfrage berechnet:

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

Die Berechnung wurde mit folgendem Code durchgeführt:

  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]

Nach der Berechnung habe ich folgende Ergebnisse erhalten:

Bildbeschreibung hier eingeben

Laut der Formel ergab sich ein Wert von 150,5, aber das Optimierungsprogramm schätzt das Prädikat auf 225,75 Zeilen. Wenn Sie den oberen Rand des Prädikats in "20140617" ändern, wertet das Optimierungsprogramm bereits 250,833 Zeilen aus, wobei nur die Formel verwendet wird, die wir erhalten 200.6666 Zeilen.

Sagen Sie mir bitte, wie bewertet Cardinality Estimator in diesem Fall? Vielleicht habe ich irgendwo einen Fehler in meinem Verständnis der angegebenen Formeln gemacht.


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

Antworten:


12

SQL Server verwendet unterschiedliche Berechnungen in unterschiedlichen Situationen. Ihr Beispiel unterscheidet sich von den verknüpften Fragen und Antworten, da Ihr Bereich vollständig in einem Schritt enthalten ist. es überschreitet keine Stufengrenze. Es ist auch ein Intervall mit zwei Enden anstatt einem. Schreiben BETWEENist dasselbe wie zwei separate Prädikate mit >=und schreiben <=.

Intervall mit zwei Grenzen in einem Schritt

Die Formel wird geändert, um eine lineare Interpolation innerhalb des Schritts für die Anzahl der erwarteten unterschiedlichen Werte durchzuführen. Dabei wird berücksichtigt, dass jetzt zwei Bereichsendpunkte angegeben werden (und davon ausgegangen wird, dass sie innerhalb des Histogrammschritts existieren), und nicht einer.

Verwenden Sie die in der Frage angegebenen Histogrammschritte:

Frage Histogramm Schritte

Für die Abfrage mit BETWEEN '20140615' AND '20140616'lautet die Berechnung:

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);

... geben 225,75 . Der Wechsel @Q2von '20140616'zu '20140617'ergibt ein Ergebnis von 250.833 .

Beide Ergebnisse stimmen mit den in der Frage angegebenen überein.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.