Betrachten Sie den unten gezeigten einfachen AdventureWorks- Abfrage- und Ausführungsplan. Die Abfrage enthält Prädikate, die mit verknüpft sind AND
. Die Kardinalitätsschätzung des Optimierers beträgt 41.211 Zeilen:
-- Estimate 41,211 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Standardstatistik verwenden
Bei nur einspaltigen Statistiken erstellt der Optimierer diese Schätzung, indem er die Kardinalität für jedes Prädikat separat schätzt und die resultierenden Selektivitäten miteinander multipliziert. Diese Heuristik geht davon aus, dass die Prädikate völlig unabhängig sind.
Durch die Aufteilung der Abfrage in zwei Teile wird die Berechnung übersichtlicher:
-- Estimate 68,336.4 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336;
Die Tabelle "Transaktionsverlauf" enthält insgesamt 113.443 Zeilen, sodass die Schätzung von 68.336,4 eine Selektivität von 68336,4 / 113443 = 0,60238533 für dieses Prädikat darstellt. Diese Schätzung wird anhand der Histogramminformationen für die TransactionID
Spalte und der in der Abfrage angegebenen Konstantenwerte ermittelt.
-- Estimate 68,413 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Dieses Prädikat hat eine geschätzte Selektivität von 68413.0 / 113443 = 0.60306056 . Es wird wiederum aus den konstanten Werten des Prädikats und dem Histogramm des TransactionDate
Statistikobjekts berechnet .
Unter der Annahme, dass die Prädikate vollständig unabhängig sind, können wir die Selektivität der beiden Prädikate zusammen schätzen, indem wir sie miteinander multiplizieren. Die endgültige Kardinalitätsschätzung wird erhalten, indem die resultierende Selektivität mit den 113.443 Zeilen in der Basistabelle multipliziert wird:
0,60238533 * 0,60306056 * 113443 = 41210,987
Nach dem Runden ist dies die Schätzung von 41.211, die in der ursprünglichen Abfrage angezeigt wird (der Optimierer verwendet auch intern Gleitkomma-Mathematik).
Keine gute Schätzung
Die Spalten TransactionID
und TransactionDate
haben eine enge Korrelation im AdventureWorks-Datensatz (wie dies bei monoton ansteigenden Schlüsseln und Datumsspalten häufig der Fall ist). Diese Korrelation bedeutet, dass die Unabhängigkeitsannahme verletzt wird. Infolgedessen enthält der Abfrageplan nach der Ausführung 68.095 Zeilen anstelle der geschätzten 41.211:
Ablaufverfolgungsflag 4137
Durch Aktivieren dieses Ablaufverfolgungsflags werden die Heuristiken geändert, die zum Kombinieren von Prädikaten verwendet werden. Anstatt völlige Unabhängigkeit anzunehmen, geht der Optimierer davon aus, dass die Selektivitäten der beiden Prädikate nahe genug beieinander liegen, sodass eine Korrelation wahrscheinlich ist:
-- Estimate 68,336.4
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13'
OPTION (QUERYTRACEON 4137);
Denken Sie daran, dass das TransactionID
Prädikat allein 68.336,4 Zeilen und das TransactionDate
Prädikat allein 68.413 Zeilen geschätzt hat. Der Optimierer hat die niedrigere dieser beiden Schätzungen gewählt, anstatt die Selektivitäten zu multiplizieren.
Dies ist natürlich nur eine andere Heuristik, die jedoch dazu beitragen kann, die Schätzungen für Abfragen mit korrelierten AND
Prädikaten zu verbessern . Jedes Prädikat wird auf mögliche Korrelation geprüft, und es werden andere Anpassungen vorgenommen, wenn viele AND
Klauseln betroffen sind. Dieses Beispiel dient jedoch dazu, die Grundlagen zu veranschaulichen.
Mehrspaltige Statistiken
Diese können bei Abfragen mit Korrelationen hilfreich sein, aber die Histogramminformationen basieren immer noch ausschließlich auf der führenden Spalte der Statistik. Die folgenden mehrspaltigen Statistikkandidaten unterscheiden sich daher in einem wichtigen Punkt:
CREATE STATISTICS
[stats Production.TransactionHistory TransactionID TransactionDate]
ON Production.TransactionHistory
(TransactionID, TransactionDate);
CREATE STATISTICS
[stats Production.TransactionHistory TransactionDate TransactionID]
ON Production.TransactionHistory
(TransactionDate, TransactionID);
Wenn wir nur eine davon nehmen, können wir sehen, dass die einzige zusätzliche Information die zusätzlichen Ebenen der "All" -Dichte sind. Das Histogramm enthält nur noch detaillierte Informationen zur TransactionDate
Spalte.
DBCC SHOW_STATISTICS
(
'Production.TransactionHistory',
'stats Production.TransactionHistory TransactionDate TransactionID'
);
Mit diesen mehrspaltigen Statistiken ...
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
... der Ausführungsplan zeigt eine Schätzung, die genau der entspricht, als nur einspaltige Statistiken verfügbar waren:
Statistics objects on multiple columns also store statistical information about the correlation of values among the columns