it-swarm.com.de

СDardinalitätsschätzung von Prädikaten mit teilweise abdeckender Reichweite

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 Kardinalitätsschätzung-für-und-für-Schritt-Statistik-Wert ​​auf eine ähnliche Frage, und Paul White gab eine ziemlich interessante Antwort darauf.

Nach der Antwort von Paulus 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) wie folgt:

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 Datenbank AdventureWorks2014 basierend auf dem Bereichsprädikat getestet Verwenden der Spalte TransactionDate und des Datums-/Uhrzeitbereichs zwischen '20140614' und '20140618'.

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

Histogram

Nach 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:

enter image description here

Gemäß der Formel stellte sich heraus, dass 150,5, aber der Optimierer schätzt das Prädikat auf 225,75 Zeilen. Wenn Sie den oberen Rand des Prädikats in '20140617' ändern, wertet der Optimierer bereits 250,833 Zeilen aus, während er nur die Formel verwendet, die wir erhalten 200.6666 Zeilen.

Bitte sagen Sie mir, wie bewertet Cardinality Estimator in diesem Fall, vielleicht habe ich irgendwo einen Fehler in meinem Verständnis der zitierten Formeln gemacht?

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. Das Schreiben von BETWEEN entspricht dem Schreiben von zwei separaten Prädikaten mit >= und <=.

Intervall mit zwei Grenzen in einem einzigen Schritt

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

Verwenden Sie die in der Frage angegebenen Histogrammschritte:

(question histogram steps

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 . Ändern @Q2 von '20140616' bis '20140617' ergibt ein Ergebnis von 250.833 .

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

13
Paul White 9