Wie wird die Anzahl der Histogrammschritte in Statistik in SQL Server festgelegt?
Warum ist es auf 200 Schritte beschränkt, obwohl meine Schlüsselspalte mehr als 200 verschiedene Werte hat? Gibt es einen entscheidenden Faktor?
Demo
Schemadefinition
CREATE TABLE histogram_step
(
id INT IDENTITY(1, 1),
name VARCHAR(50),
CONSTRAINT pk_histogram_step PRIMARY KEY (id)
)
Einfügen von 100 Datensätzen in meine Tabelle
INSERT INTO histogram_step
(name)
SELECT TOP 100 name
FROM sys.syscolumns
Aktualisieren und Überprüfen der Statistiken
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Histogrammschritte:
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 3 | 1 | 1 | 1 | 1 |
| 5 | 1 | 1 | 1 | 1 |
| 7 | 1 | 1 | 1 | 1 |
| 9 | 1 | 1 | 1 | 1 |
| 11 | 1 | 1 | 1 | 1 |
| 13 | 1 | 1 | 1 | 1 |
| 15 | 1 | 1 | 1 | 1 |
| 17 | 1 | 1 | 1 | 1 |
| 19 | 1 | 1 | 1 | 1 |
| 21 | 1 | 1 | 1 | 1 |
| 23 | 1 | 1 | 1 | 1 |
| 25 | 1 | 1 | 1 | 1 |
| 27 | 1 | 1 | 1 | 1 |
| 29 | 1 | 1 | 1 | 1 |
| 31 | 1 | 1 | 1 | 1 |
| 33 | 1 | 1 | 1 | 1 |
| 35 | 1 | 1 | 1 | 1 |
| 37 | 1 | 1 | 1 | 1 |
| 39 | 1 | 1 | 1 | 1 |
| 41 | 1 | 1 | 1 | 1 |
| 43 | 1 | 1 | 1 | 1 |
| 45 | 1 | 1 | 1 | 1 |
| 47 | 1 | 1 | 1 | 1 |
| 49 | 1 | 1 | 1 | 1 |
| 51 | 1 | 1 | 1 | 1 |
| 53 | 1 | 1 | 1 | 1 |
| 55 | 1 | 1 | 1 | 1 |
| 57 | 1 | 1 | 1 | 1 |
| 59 | 1 | 1 | 1 | 1 |
| 61 | 1 | 1 | 1 | 1 |
| 63 | 1 | 1 | 1 | 1 |
| 65 | 1 | 1 | 1 | 1 |
| 67 | 1 | 1 | 1 | 1 |
| 69 | 1 | 1 | 1 | 1 |
| 71 | 1 | 1 | 1 | 1 |
| 73 | 1 | 1 | 1 | 1 |
| 75 | 1 | 1 | 1 | 1 |
| 77 | 1 | 1 | 1 | 1 |
| 79 | 1 | 1 | 1 | 1 |
| 81 | 1 | 1 | 1 | 1 |
| 83 | 1 | 1 | 1 | 1 |
| 85 | 1 | 1 | 1 | 1 |
| 87 | 1 | 1 | 1 | 1 |
| 89 | 1 | 1 | 1 | 1 |
| 91 | 1 | 1 | 1 | 1 |
| 93 | 1 | 1 | 1 | 1 |
| 95 | 1 | 1 | 1 | 1 |
| 97 | 1 | 1 | 1 | 1 |
| 99 | 1 | 1 | 1 | 1 |
| 100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Wie wir sehen können, enthält das Histogramm 53 Schritte.
Wieder ein paar tausend Datensätze einfügen
INSERT INTO histogram_step
(name)
SELECT TOP 10000 b.name
FROM sys.syscolumns a
CROSS JOIN sys.syscolumns b
Aktualisieren und Überprüfen der Statistiken
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Jetzt werden die Histogrammschritte auf 4 Schritte reduziert
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 10088 | 10086 | 1 | 10086 | 1 |
| 10099 | 10 | 1 | 10 | 1 |
| 10100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Wieder ein paar tausend Datensätze einfügen
INSERT INTO histogram_step
(name)
SELECT TOP 100000 b.name
FROM sys.syscolumns a
CROSS JOIN sys.syscolumns b
Aktualisieren und Überprüfen der Statistiken
UPDATE STATISTICS histogram_step WITH fullscan
DBCC show_statistics('histogram_step', pk_histogram_step)
Jetzt werden die Histogrammschritte auf 3 Schritte reduziert
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
| 110099 | 110097 | 1 | 110097 | 1 |
| 110100 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Kann mir jemand sagen, wie diese Schritte entschieden werden?
quelle
Antworten:
Ich werde diesen Beitrag auf die Erörterung einspaltiger Statistiken beschränken, da er bereits ziemlich langwierig ist und Sie daran interessiert sind, wie SQL Server die Daten in Histogrammschritte unterteilt. Bei mehrspaltigen Statistiken wird das Histogramm nur in der führenden Spalte erstellt.
Wenn SQL Server feststellt, dass eine Statistikaktualisierung erforderlich ist, wird eine versteckte Abfrage gestartet, die entweder alle Daten einer Tabelle oder ein Beispiel der Daten der Tabelle liest. Sie können diese Abfragen mit erweiterten Ereignissen anzeigen. In
StatMan
SQL Server wird eine Funktion aufgerufen , die an der Erstellung der Histogramme beteiligt ist. Für einfache Statistikobjekte gibt es mindestens zwei verschiedene Arten vonStatMan
Abfragen (es gibt verschiedene Abfragen für schnelle Statistikaktualisierungen, und ich vermute, dass die Funktion für inkrementelle Statistiken in partitionierten Tabellen auch eine andere Abfrage verwendet).Der erste erfasst einfach alle Daten aus der Tabelle ohne Filterung. Sie können dies sehen, wenn die Tabelle sehr klein ist oder Sie Statistiken mit der
FULLSCAN
Option sammeln :SQL Server wählt die automatische Stichprobengröße basierend auf der Größe der Tabelle aus (ich denke, dass dies sowohl die Anzahl der Zeilen als auch der Seiten in der Tabelle ist). Wenn eine Tabelle zu groß ist, fällt die automatische Stichprobengröße unter 100%. Folgendes habe ich für dieselbe Tabelle mit 1 Million Zeilen erhalten:
TABLESAMPLE
ist dokumentiert , StatMan und step_direction jedoch nicht. Hier tastet SQL Server etwa 66,6% der Daten aus der Tabelle ab, um das Histogramm zu erstellen. Dies bedeutet, dass Sie möglicherweise eine andere Anzahl von Histogrammschritten erhalten, wenn Sie Statistiken (ohneFULLSCAN
) für dieselben Daten aktualisieren . Ich habe das in der Praxis nie beobachtet, aber ich verstehe nicht, warum es nicht möglich wäre.Lassen Sie uns einige Tests mit einfachen Daten durchführen, um zu sehen, wie sich die Statistiken im Laufe der Zeit ändern. Im Folgenden finden Sie einen Testcode, den ich geschrieben habe, um sequentielle Ganzzahlen in eine Tabelle einzufügen, Statistiken nach jeder Einfügung zu sammeln und Informationen zu den Statistiken in einer Ergebnistabelle zu speichern. Beginnen wir mit dem Einfügen von jeweils 1 Zeile bis zu 10000. Prüfstand:
Für diese Daten steigt die Anzahl der Histogrammschritte schnell auf 200 (zuerst wird die maximale Anzahl von Schritten mit 397 Zeilen erreicht), bleibt bei 199 oder 200, bis 1485 Zeilen in der Tabelle enthalten sind, und nimmt dann langsam ab, bis das Histogramm nur noch 3 oder 4 enthält Schritte. Hier ist eine Grafik aller Daten:
So sieht das Histogramm für 10.000 Zeilen aus:
Ist es ein Problem, dass das Histogramm nur 3 Schritte hat? Es sieht so aus, als ob Informationen aus unserer Sicht erhalten bleiben. Da der Datentyp ein INTEGER ist, können wir herausfinden, wie viele Zeilen in der Tabelle für jede Ganzzahl von 1 bis 10000 enthalten sind. In der Regel kann SQL Server dies auch herausfinden, obwohl dies in einigen Fällen nicht ganz funktioniert . In diesem SE-Beitrag finden Sie ein Beispiel dafür.
Was wird Ihrer Meinung nach passieren, wenn wir eine einzelne Zeile aus der Tabelle löschen und die Statistiken aktualisieren? Idealerweise erhalten wir einen weiteren Histogrammschritt, um zu zeigen, dass die fehlende Ganzzahl nicht mehr in der Tabelle enthalten ist.
Das ist ein bisschen enttäuschend. Wenn wir ein Histogramm von Hand erstellen würden, würden wir für jeden fehlenden Wert einen Schritt hinzufügen. SQL Server verwendet einen Allzweckalgorithmus, sodass wir für einige Datensätze möglicherweise ein geeigneteres Histogramm als den von ihm verwendeten Code erstellen können. Natürlich ist der praktische Unterschied zwischen 0 oder 1 Zeile aus einer Tabelle sehr gering. Ich erhalte die gleichen Ergebnisse beim Testen mit 20000 Zeilen, wobei jede Ganzzahl 2 Zeilen in der Tabelle enthält. Das Histogramm erhält keine Schritte, wenn ich Daten lösche.
Wenn ich mit 1 Million Zeilen teste, wobei jede Ganzzahl 100 Zeilen in der Tabelle enthält, erhalte ich etwas bessere Ergebnisse, kann aber dennoch von Hand ein besseres Histogramm erstellen.
Endgültiges Histogramm:
Lassen Sie uns weiter mit sequentiellen Ganzzahlen, aber mit mehr Zeilen in der Tabelle testen. Beachten Sie, dass die manuelle Angabe einer Stichprobengröße für zu kleine Tabellen keine Auswirkung hat. Daher füge ich jeder Einfügung 100 Zeilen hinzu und sammle jedes Mal Statistiken mit bis zu 1 Million Zeilen. Ich sehe ein ähnliches Muster wie zuvor, außer wenn ich 637300 Zeilen in der Tabelle erreicht habe, werden nicht mehr 100% der Zeilen in der Tabelle mit der Standardabtastrate abgetastet. Wenn ich Zeilen gewinne, nimmt die Anzahl der Histogrammschritte zu. Möglicherweise liegt dies daran, dass SQL Server mit zunehmender Anzahl nicht abgetasteter Zeilen in der Tabelle mehr Lücken in den Daten aufweist. Ich treffe selbst bei 1 M Reihen nicht 200 Schritte, aber wenn ich weiterhin Reihen hinzufüge, erwarte ich, dass ich dort ankomme und irgendwann wieder nach unten gehe.
Die X-Achse ist die Anzahl der Zeilen in der Tabelle. Wenn die Anzahl der Zeilen zunimmt, variieren die abgetasteten Zeilen ein wenig und überschreiten nicht 650.000.
Lassen Sie uns nun einige einfache Tests mit VARCHAR-Daten durchführen.
Hier füge ich 200 Zahlen (als Zeichenfolgen) zusammen mit NULL ein.
Beachten Sie, dass NULL immer einen eigenen Histogrammschritt erhält, wenn er in der Tabelle gefunden wird. SQL Server hätte mir genau 201 Schritte geben können, um alle Informationen zu erhalten, aber das hat es nicht getan. Technisch gesehen gehen Informationen verloren, weil '1111' beispielsweise zwischen '1' und '2' sortiert.
Versuchen wir nun, verschiedene Zeichen anstelle von ganzen Zahlen einzufügen:
Kein wirklicher Unterschied zum letzten Test.
Versuchen wir nun, Zeichen einzufügen, aber unterschiedliche Nummern für jedes Zeichen in die Tabelle aufzunehmen. Hat zum Beispiel
CHAR(11)
1 Zeile,CHAR(12)
hat 2 Zeilen usw.Nach wie vor bekomme ich immer noch nicht genau 200 Histogrammschritte. Viele der Schritte haben jedoch
RANGE_ROWS
0.Für den letzten Test werde ich eine zufällige Zeichenfolge mit 5 Zeichen in jede Schleife einfügen und jedes Mal Statistiken sammeln. Hier ist der Code der zufälligen Zeichenfolge:
Hier ist das Diagramm der Zeilen in Tabellen- und Histogrammschritten:
Beachten Sie, dass die Anzahl der Schritte nicht unter 100 sinkt, sobald sie auf und ab gehen. Ich habe von irgendwoher gehört (kann es aber momentan nicht beziehen), dass der SQL Server-Algorithmus zum Erstellen von Histogrammen Histogrammschritte kombiniert, da kein Platz mehr für sie vorhanden ist. Sie können also drastische Änderungen in der Anzahl der Schritte vornehmen, indem Sie nur ein paar Daten hinzufügen. Hier ist ein Beispiel der Daten, die ich interessant fand:
Selbst beim Abtasten mit
FULLSCAN
kann das Hinzufügen einer einzelnen Zeile die Anzahl der Schritte um 10 erhöhen, konstant halten, dann um 2 verringern und dann um 3 verringern.Was können wir daraus zusammenfassen? Ich kann nichts davon beweisen, aber diese Beobachtungen scheinen zuzutreffen:
RANGE_ROWS
= 0.RANGE_HI_KEY
in der Tabelle.DISTINCT_RANGE_ROWS
oder wiederholtRANGE_ROWS
. Zum Beispiel wird 255 einige Male fürRANGE_ROWS
undDISTINCT_RANGE_ROWS
für den endgültigen Testfall hier angezeigt.Wann ist das alles ein Problem? Es ist ein Problem, wenn eine Abfrage aufgrund eines Histogramms, das die Datenverteilung nicht so darstellen kann, dass das Abfrageoptimierungsprogramm gute Entscheidungen treffen kann, eine schlechte Leistung erbringt. Ich denke, es besteht die Tendenz zu denken, dass es immer besser ist, mehr Histogrammschritte zu haben, und dass es Bestürzung gibt, wenn SQL Server ein Histogramm für Millionen von Zeilen oder mehr generiert, aber nicht genau 200 oder 201 Histogrammschritte verwendet. Ich habe jedoch viele Statistikprobleme gesehen, selbst wenn das Histogramm 200 oder 201 Schritte hat. Wir haben keine Kontrolle darüber, wie viele Histogrammschritte SQL Server für ein Statistikobjekt generiert, sodass ich mir darüber keine Sorgen machen würde. Es gibt jedoch einige Schritte, die Sie ausführen können, wenn Abfragen mit schlechter Leistung aufgrund von Statistikproblemen auftreten. Ich werde einen äußerst kurzen Überblick geben.
In einigen Fällen kann es hilfreich sein, Statistiken vollständig zu sammeln. Bei sehr großen Tabellen kann die automatische Stichprobengröße weniger als 1% der Zeilen in der Tabelle betragen. Abhängig von der Datenstörung in der Spalte kann dies manchmal zu schlechten Plänen führen. Die Dokumentation von Microsoft für CREATE STATISTICS und UPDATE STATISTICS lautet wie folgt:
In einigen Fällen kann das Erstellen gefilterter Statistiken hilfreich sein. Möglicherweise haben Sie eine Spalte mit verzerrten Daten und vielen verschiedenen unterschiedlichen Werten. Wenn die Daten bestimmte Werte enthalten, nach denen häufig gefiltert wird, können Sie ein Statistikhistogramm nur für diese allgemeinen Werte erstellen. Das Abfrageoptimierungsprogramm kann die für einen kleineren Datenbereich definierten Statistiken anstelle der für alle Spaltenwerte definierten Statistiken verwenden. Es ist immer noch nicht garantiert, dass Sie 200 Schritte im Histogramm erhalten. Wenn Sie jedoch die gefilterten Statistiken für nur einen Wert erstellen, wird ein Histogramm diesen Wert schrittweise ausführen.
Die Verwendung einer partitionierten Ansicht ist eine Möglichkeit, mehr als 200 Schritte für eine Tabelle effektiv abzurufen. Angenommen, Sie können einen großen Tisch problemlos in einen Tisch pro Jahr aufteilen. Sie erstellen eine
UNION ALL
Ansicht, in der alle Jahrestabellen zusammengefasst sind. Jede Tabelle hat ein eigenes Histogramm. Beachten Sie, dass die in SQL Server 2014 eingeführten neuen inkrementellen Statistiken nur eine effizientere Aktualisierung der Statistiken ermöglichen. Das Abfrageoptimierungsprogramm verwendet nicht die Statistiken, die pro Partition erstellt werden.Es gibt noch viele weitere Tests, die hier durchgeführt werden könnten. Ich empfehle Ihnen daher, zu experimentieren. Ich habe diese Tests mit SQL Server 2014 Express durchgeführt, sodass Sie wirklich nichts mehr aufhält.
quelle