SQL Server: Genaue Zeilenschätzungen ohne Histogramm?

7

Ich untersuche das Optimierungsprogramm in SQL Server, insbesondere Histogramme, und sehe einige seltsame Ergebnisse.

Wenn ich die folgende Abfrage ausführe, bei der ich weiß, dass das Feld kein Histogramm enthält, gibt SQL Server eine Zeilenschätzung aus, die dem tatsächlichen Ergebnis entspricht. Wenn ich dieselbe Abfrage ausführen würde, bei der ich DECLARE @i NUMERIC(19,2) = 30.0anstelle einer Konstanten verwende WHERE [Rate] < @i, entspricht die Schätzung 94.8der erwarteten Abfrage, da die Datenbank keine Statistiken für das Feld enthält.

Schätzung der Abfrage

Meine Frage ist also, warum SQL Server das richtige Ergebnis ausgibt, wenn keine Statistiken auf dem Feld vorhanden sind.


Beim Ausschalten, AUTO_CREATE_STATISTICSwie in meiner Antwort angegeben, tritt bei den Zeilenschätzungen ein merkwürdiges Verhalten auf.

In der Tabelle ist eine Einschränkung vorhanden, die darauf beschränkt ist [Rate], zwischen zu liegen 6.5 - 200.0. Die Schätzungen variieren stark , wenn je nach experimentieren , wenn >verwendet wird , oder >=sowie 24.0oder 64Format - Abfragen , wo das Prädikat zeigt eine implict Umwandlung zu geben money.

Denn WHERE [Rate] > 6.5die Schätzung ist, 28.44welche dann bei Raten über stoppt 100.

Wenn WHERE [Rate] > 7Dezimalstellen ausgeschlossen sind, 28.44läuft die Schätzung bis zu255

Denn WHERE [Rate] >= 6.5die 28.44Schätzung läuft bis zu ungefähr 100und ändert sich dann 17.7764bis zu, 1000bevor die Schätzung auf 1 fällt.

Es scheint also nicht viel Konsistenz zu geben. Anscheinend ist sich SQL Server der Einschränkung bewusst, die auf einigen der Abfragen basiert, mit denen ich experimentiere, aber es ignoriert manchmal auch deren Vorhandensein.

Duane
quelle

Antworten:

13

Wie Sie bereits bemerkt haben, erstellt SQL Server beim Kompilieren eines Ausführungsplans automatisch fehlende Statistiken (sofern möglich), sofern die Datenbankoption aktiviert AUTO_CREATE_STATISTICSist.

Wenn keine Statistiken verfügbar sind, beträgt die Standardschätzung für ein unbekanntes Ungleichheitsprädikat 0,3 (30%). Wenn Sie eine lokale Variable verwenden, kann der Wert in der Variablen nicht abgehört werden (es OPTION (RECOMPILE)sei denn, dies ist ebenfalls angegeben). Bei einer Tabellenkardinalität von 316 beträgt die Schätzung 0,3 * 316 = 94,8.

Wenn Sie ein konstantes Literal verwenden, wird der Wert abgehört. Ohne Statistik kann es diesen Sniffed-Wert nicht verwenden, um das Histogramm wie gewohnt zu überprüfen, aber es kann seine Auswirkungen auf die CHECKEinschränkung beurteilen (die eine, die die Rate-Werte auf 6,50 bis 200 US-Dollar begrenzt).

Wenn der Sniffed-Wert den Prüfbeschränkungsbereich nicht vollständig ausschließt , basiert die Schätzung auf der erratenen Selektivität von 0,09 (9%) für ein BETWEENPrädikat (aus der Prüfbeschränkung). 316 * 0,09 = 28,44.

Wenn der Sniffed-Wert den Prüfbeschränkungsbereich vollständig ausschließt, beträgt die Schätzung immer 1 Zeile (der Kardinalitätsschätzer erzeugt (fast) nie eine geschätzte Anzahl von Zeilen unter 1).

Wenn die Abfrage einfach genug ist, um sich für einen trivialen Plan zu qualifizieren, und für eine einfache Parametrisierung als sicher angesehen wird, wird das konstante Literal durch eine Parametermarkierung ersetzt, z @1. Dies geschieht für eine Abfrage wie:

SELECT * 
FROM HumanResources.EmployeePayHistory AS EPH 
WHERE EPH.Rate > $200;

Der Ausführungsplan zeigt eine Schätzung von 1 Zeile:

Planen

Und das Scan-Prädikat zeigt eine Parametermarkierung:

Eigenschaften

Wenn eine einfache Parametrisierung verhindert wird, z. B. durch Hinzufügen einer Klausel, die eine Konstante mit einer Konstanten vergleicht:

SELECT * 
FROM HumanResources.EmployeePayHistory AS EPH 
WHERE EPH.Rate > $200
AND 1 = 1;

Ohne Parametrisierung kann dieser Plan niemals mit einem anderen Wert für den Parameter wiederverwendet werden, sodass der Optimierer den Tabellenzugriff statisch eliminieren kann, da die Prüfbeschränkung die Rückgabe von Zeilen verhindert. Der Resuting-Plan lautet:

Ständiger Scan

Seien Sie schließlich vorsichtig mit Typen. Der Typ der Rate-Spalte ist Geld , nicht dezimal . Konvertierungen können die Kardinalitätsschätzung auf komplizierte Weise beeinflussen. Geben Sie eine Geld wörtlichen mit dem Präfix $, oder verwenden Sie eine explizite CASToder CONVERT.


Die internen Details der Kardinalitätsschätzung werden nicht öffentlich dokumentiert (wahrscheinlich, um endlose, immer detailliertere Fragen und Beschwerden zu vermeiden, wenn sich die Dinge ändern), aber es gibt eine Reihe von Ressourcen, die Ihnen in diesem Bereich helfen können. Denken Sie daran, dass das meiste davon inoffiziell ist und daher von niemandem unterstützt wird. Einige Aspekte sind tatsächlich gefährlich.

Einige gelten nur für den ursprünglichen Kardinalitätsschätzer (vor 2014), andere erläutern allgemeine Grundsätze, die für beide gelten, und andere gelten nur für das "neue" CE. Das Folgende ist nicht als maßgebliche oder vollständige Liste gedacht, sondern nur als solche, die sofort in den Sinn kamen:

Paul White 9
quelle
1

Was mir aufgefallen ist, ist, dass AUTO_CREATE_STATISTICSSQL Server , wenn es aktiviert ist, das Histogramm auf dem Feld stillschweigend berechnet, bevor ich die Abfrage ausführe.

Wenn ich AUTO_CREATE_STATISTICSdieselbe Abfrage ausschalte und ausführe, erhalte ich eine viel plausibelere Schätzung (wenn man bedenkt, dass sie keine Statistiken enthält). Siehe unten:

Automatisch erstellen aus

Duane
quelle