Wie wichtig ist die Reihenfolge der Spalten in Indizes?

173

Ich habe gehört, dass Sie zu Beginn der Indexdeklaration Spalten einfügen sollten, die am selektivsten sind. Beispiel:

CREATE NONCLUSTERED INDEX MyINDX on Table1
(
   MostSelective,
   SecondMost,
   Least
)

Ist das, was ich sage, richtig? Wenn ja, sehe ich wahrscheinlich große Leistungsunterschiede, wenn ich die Reihenfolge der Spalten in meinem Index neu ordne, oder ist es eher eine "nette Aufgabe"?

Der Grund, den ich frage, ist, dass nach dem Durchführen einer Abfrage durch den DTA empfohlen wurde, einen Index zu erstellen, der fast alle gleichen Spalten wie ein vorhandener Index enthält, nur in einer anderen Reihenfolge. Ich dachte darüber nach, nur die fehlenden Spalten zum vorhandenen Index hinzuzufügen und ihn als gut zu bezeichnen. Gedanken?

Abe Miessler
quelle

Antworten:

193

Sehen Sie sich einen Index wie diesen an:

Cols
  1   2   3
-------------
|   | 1 |   |
| A |---|   |
|   | 2 |   |
|---|---|   |
|   |   |   |
|   | 1 | 9 |
| B |   |   |
|   |---|   |
|   | 2 |   |
|   |---|   |
|   | 3 |   |
|---|---|   |

Sehen Sie, wie die Einschränkung von A zuerst, da Ihre erste Spalte mehr Ergebnisse eliminiert als die Einschränkung Ihrer zweiten Spalte zuerst? Es ist einfacher, wenn Sie sich vorstellen, wie der Index durchlaufen werden muss, Spalte 1, dann Spalte 2 usw. Sie sehen, dass das Abschalten der meisten Ergebnisse im ersten Durchgang den zweiten Schritt so viel schneller macht.

In einem anderen Fall würde der Optimierer bei einer Abfrage in Spalte 3 nicht einmal den Index verwenden, da dies bei der Eingrenzung der Ergebnismengen überhaupt nicht hilfreich ist. Immer wenn Sie sich in einer Abfrage befinden, bedeutet eine Einschränkung der Anzahl der Ergebnisse, die vor dem nächsten Schritt verarbeitet werden müssen, eine bessere Leistung.

Da der Index auch auf diese Weise gespeichert wird, gibt es kein Zurückverfolgen des Index, um die erste Spalte zu finden, wenn Sie danach fragen.

Kurz gesagt: Nein, es ist nicht für die Show, es gibt echte Leistungsvorteile.

Nick Craver
quelle
13
Beachten Sie im obigen Bild, dass dieser Index nur dann von Vorteil ist, wenn Spalte 1 in der Abfrage angegeben wurde. Wenn Ihre Abfrage nur Spalte 2 im Join- oder Suchprädikat angibt, ist dies nicht vorteilhaft. Ordnung ist also auch dort wichtig. Vielleicht ist das selbstverständlich, wollte es aber erwähnen.
CodeCowboyOrg
3
Denken Sie auch daran, dass Ihr Index dem obigen Bild entspricht und Ihre Abfrage nach Spalte1 und Spalte2 filtert, Spalte2 jedoch eindeutiger ist und Sie wirklich nach Spalte2 filtern möchten. Dann ist es vorteilhafter, nur einen Index zu haben, in dem Spalte 2 ist zuerst. Dies mag nicht intuitiv erscheinen, aber denken Sie daran, dass ein Index auf mehreren Seiten gespeichert ist und ein Baum mit einem Wertebereich ist, während Spalte 1 oben die Hälfte der Möglichkeiten negiert. Der Index weiß bereits, zu welcher Indexseite er direkt wechseln soll Für den Wert von Spalte 2 ist Spalte 1 nicht erforderlich, um die Menge einzugrenzen.
CodeCowboyOrg
4
Dieses Bild ist keine genaue Darstellung der Struktur oder Navigation von Indizes. Haben eine Antwort eingereicht, die diesen stackoverflow.com/a/39080819/73226
Martin Smith
6
@ MartinSmith Ich bin nicht einverstanden, dass es ungenau ist. Es ist zugegebenermaßen extrem vereinfacht, was meine Absicht war. Ihre Antwort, die sich viel detaillierter mit den Levels befasst, wird jedoch für diejenigen geschätzt, die tiefer in sie eintauchen möchten. Wenn Sie sich Ihr Baumbild ansehen, werden Sie auf sehr einfache Weise sehen, was ich illustriere . Dies ist nicht sehr einzigartig oder sogar SQL-spezifisch. B-Tree-Indizierung ist in so vielen Dingen ziemlich verbreitet.
Nick Craver
@MartinSmith Ich würde auch nicht zustimmen, dass es ungenau ist. Was Sie beschreiben, ist das Standardverhalten bei der Ermittlung des Index - Selektivität ist viel wichtiger, wenn Sie Bereichsabfragen durchführen, da dies die Anzahl der Indexseiten minimiert, die der Optimierer benötigt muss scannen; Dies kann in großen Tabellen mit Millionen von Zeilen von Bedeutung sein
Paul Hatcher
127

Die Reihenfolge der Spalten ist kritisch. Welche Reihenfolge nun korrekt ist, hängt davon ab, wie Sie sie abfragen. Ein Index kann verwendet werden, um eine genaue Suche oder einen Bereichsscan durchzuführen. Eine genaue Suche ist, wenn Werte für alle Spalten im Index angegeben werden und die Abfrage genau in der Zeile landet, an der sie interessiert ist. Für Suchen ist die Reihenfolge der Spalten irrelevant. Bei einem Bereichsscan werden nur einige Spalten angegeben, und in diesem Fall wird die Reihenfolge wichtig. SQL Server kann einen Index für einen Bereichsscan nur verwenden, wenn die Spalte ganz links angegeben ist, und nur dann, wenn die nächste Spalte ganz links angegeben ist, und so weiter. Wenn Sie einen Index für (A, B, C) haben, können Sie damit den Bereichssuchlauf für A=@a, A=@a AND B=@baber nicht für B=@b, für C=@cnoch durchführen B=@b AND C=@c. Der Fall A=@a AND C=@cist gemischt, wie in derA=@aTeil verwendet den Index, aberC=@cnicht (die Abfrage durchsucht alle B-Werte nach A=@a, springt nicht zu C=@c). Andere Datenbanksysteme verfügen über den sogenannten "Skip Scan" -Operator, der die inneren Spalten in einem Index nutzen kann, wenn die äußeren Spalten nicht angegeben sind.

Mit diesem Wissen können Sie sich die Indexdefinitionen noch einmal ansehen. Ein Index für (MostSelective, SecondMost, Least)ist nur wirksam, wenn eine MostSelectiveSpalte angegeben ist. Da dies jedoch am selektivsten ist, wird sich die Relevanz der inneren Säulen schnell verschlechtern. Sehr oft werden Sie feststellen , dass ein besserer Index auf (MostSelective) include (SecondMost, Least)oder auf (MostSelective, SecondMost) include (Least). Da die inneren Spalten weniger relevant sind, führt das Platzieren von Spalten mit geringer Selektivität an solchen richtigen Positionen im Index zu nichts als Rauschen für eine Suche. Daher ist es sinnvoll, sie aus den Zwischenseiten zu verschieben und sie nur auf den Blattseiten zu belassen, z Abdeckbarkeit der Abfrage. Mit anderen Worten, verschieben Sie sie in INCLUDE. Dies wird mit der Größe von wichtigerLeast Spaltengröße . Die Idee ist, dass dieser Index nur Abfragen zugute kommen kann, die angebenMostSelective entweder als exakter Wert oder als Bereich, und diese Spalte ist die selektivste, die die Kandidatenzeilen bereits stark einschränkt.

Auf der anderen Seite (Least, SecondMost, MostSelective)mag ein Index auf ein Fehler sein, aber es ist tatsächlich ein ziemlich mächtiger Index. Da die LeastSpalte die äußerste Abfrage ist, kann sie für Abfragen verwendet werden, bei denen Ergebnisse in Spalten mit geringer Selektivität zusammengefasst werden müssen. Solche Abfragen sind in OLAP- und Analyse-Data-Warehouses weit verbreitet, und genau hier haben solche Indizes einen sehr guten Grund. Solche Indizes sind tatsächlich hervorragende Clustered- Indizes, gerade weil sie das physische Layout in großen Abschnitten verwandter Zeilen organisieren (gleicher LeastWert, der normalerweise eine Kategorie oder einen Typ angibt) und Analyseabfragen erleichtern.

Es gibt also leider keine "richtige" Reihenfolge. Sie sollten kein Rezept für einen Ausstecher befolgen, sondern das Abfragemuster, das Sie verwenden möchten, anhand dieser Tabellen analysieren und entscheiden, welche Indexspaltenreihenfolge richtig ist.

Remus Rusanu
quelle
3
Tolle Resonanz wie immer Remus. Ich werde Ihren dritten Absatz noch ein paar Mal durchlesen und nachverfolgen. Ich vermute, dass das genau das ist, was ich tun muss.
Abe Miessler
"SQL Server kann einen Index für einen Bereichsscan nur verwenden, wenn die Spalte ganz links angegeben ist, und nur dann, wenn die nächste Spalte ganz links angegeben ist, und so weiter." Genau das fehlte mir, danke! Ich wusste nicht, dass Bereichsscans nur für die am weitesten rechts verwendete Indexspalte durchgeführt werden können, aber jetzt, wo ich das mache, macht es so viel Sinn.
Allon Guralnek
Gilt diese Erklärung für Oracle DB?
weiterer
1
@Roizpi Ja, im Grunde funktioniert jede Beziehungsdatenbank mit Indizes gleich oder sehr ähnlich.
Tatranskymedved
45

Wie Remus sagt, hängt es von Ihrer Arbeitsbelastung ab.

Ich möchte jedoch einen irreführenden Aspekt der akzeptierten Antwort ansprechen.

Bei Abfragen, die eine Gleichheitssuche für alle Spalten im Index durchführen, gibt es keinen signifikanten Unterschied.

Im Folgenden werden zwei Tabellen erstellt und mit identischen Daten gefüllt. Der einzige Unterschied besteht darin, dass bei einem die Schlüssel von am meisten bis am wenigsten selektiv und bei dem anderen umgekehrt angeordnet sind.

CREATE TABLE Table1(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);
CREATE TABLE Table2(MostSelective char(800), SecondMost TINYINT, Least  CHAR(1), Filler CHAR(4000) null);

CREATE NONCLUSTERED INDEX MyINDX on Table1(MostSelective,SecondMost,Least);
CREATE NONCLUSTERED INDEX MyINDX2 on Table2(Least,SecondMost,MostSelective);

INSERT INTO Table1 (MostSelective, SecondMost, Least)
output inserted.* into Table2
SELECT TOP 26 REPLICATE(CHAR(number + 65),800), number/5, '~'
FROM master..spt_values
WHERE type = 'P' AND number >= 0
ORDER BY number;

Führen Sie jetzt eine Abfrage für beide Tabellen durch ...

SELECT *
FROM   Table1
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~';

SELECT *
FROM   Table2
WHERE  MostSelective = REPLICATE('P', 800)
       AND SecondMost = 3
       AND Least = '~'; 

... Beide verwenden eine Indexstrafe und beide erhalten genau die gleichen Kosten.

Geben Sie hier die Bildbeschreibung ein

Die ASCII-Kunst in der akzeptierten Antwort ist nicht die Struktur der Indizes. Die Indexseiten für Tabelle 1 sind unten dargestellt (klicken Sie auf das Bild, um es in voller Größe zu öffnen).

Geben Sie hier die Bildbeschreibung ein

Die Indexseiten enthalten Zeilen, die den gesamten Schlüssel enthalten (in diesem Fall wird tatsächlich eine zusätzliche Schlüsselspalte für die Zeilenkennung angehängt, da der Index nicht als eindeutig deklariert wurde, aber dies kann ignoriert werden. Weitere Informationen hierzu finden Sie hier ).

Bei der obigen Abfrage kümmert sich SQL Server nicht um die Selektivität der Spalten. Es führt eine binäre Suche auf der Stammseite durch und stellt fest, dass der Schlüssel vorhanden (PPP...,3,~ ) ist, >=(JJJ...,1,~ )und < (SSS...,3,~ )sollte daher die Seite lesen 1:118. Anschließend werden die Schlüsseleinträge auf dieser Seite binär durchsucht und die Blattseite gefunden, zu der nach unten gewechselt werden soll.

Das Ändern des Index in der Reihenfolge der Selektivität wirkt sich weder auf die erwartete Anzahl der Schlüsselvergleiche aus der binären Suche noch auf die Anzahl der Seiten aus, die für eine Indexsuche navigiert werden müssen. Bestenfalls könnte dies den Schlüsselvergleich selbst geringfügig beschleunigen.

Manchmal ist es jedoch sinnvoll, zuerst den selektivsten Index zu bestellen, um andere Abfragen in Ihrer Workload durchzuführen.

Beispiel: Wenn die Arbeitslast Abfragen der beiden folgenden Formulare enthält.

SELECT * ... WHERE  MostSelective = 'P'

SELECT * ...WHERE Least = '~'

Die obigen Indizes decken keinen von beiden ab. MostSelectiveist selektiv genug, um einen Plan mit einer Suche und Suche zu erstellen, die sich lohnt, aber die Abfrage dagegen Leastist es nicht.

Dieses Szenario (nicht abdeckende Indexsuche für Teilmenge führender Spalten eines zusammengesetzten Index) ist jedoch nur eine mögliche Abfrageklasse, die von einem Index unterstützt werden kann. Wenn Sie niemals MostSelectivealleine oder in einer Kombination von MostSelective, SecondMostund immer nach einer Kombination aller drei Spalten suchen, ist dieser theoretische Vorteil für Sie nutzlos.

Umgekehrt Abfragen wie

SELECT MostSelective,
       SecondMost,
       Least
FROM   Table2
WHERE  Least = '~'
ORDER  BY SecondMost,
          MostSelective 

Wäre hilfreich, wenn die umgekehrte Reihenfolge der üblicherweise vorgeschriebenen verwendet würde - da diese die Abfrage abdeckt, kann sie eine Suche unterstützen und Zeilen in der gewünschten Reihenfolge zum Booten zurückgeben.

Dies ist also ein oft wiederholter Ratschlag, aber höchstens eine Heuristik über den potenziellen Nutzen anderer Abfragen - und es ist kein Ersatz dafür, Ihre Arbeitsbelastung tatsächlich zu betrachten .

Martin Smith
quelle
31

Sie sollten am Anfang der Indexdeklaration Spalten einfügen, die am selektivsten sind.

Richtig. Indizes können zusammengesetzte Elemente sein, die aus mehreren Spalten bestehen. Die Reihenfolge ist aufgrund des Prinzips ganz links wichtig. Grund dafür ist, dass die Datenbank die Liste von links nach rechts überprüft und eine entsprechende Spaltenreferenz finden muss, die der definierten Reihenfolge entspricht. Beispiel: Ein Index für eine Adresstabelle mit Spalten:

  • Adresse
  • Stadt
  • Zustand

Jede Abfrage, die die addressSpalte verwendet, kann den Index verwenden. Wenn die Abfrage jedoch nur entweder cityund / oder stateReferenzen enthält, kann der Index nicht verwendet werden. Dies liegt daran, dass auf die Spalte ganz links nicht verwiesen wird. Die Abfrageleistung sollte Ihnen sagen, welche optimal ist - einzelne Indizes oder mehrere Verbundwerkstoffe mit unterschiedlicher Reihenfolge. Gut gelesen: The Tipping Point von Kimberley Tripp

OMG Ponys
quelle
Was wäre, wenn nur die Spalte ganz rechts nicht verwendet würde? Eine Abfrage verwendete also Adresse und Stadt, aber NICHT den Status. Würde der Index dann verwendet werden?
Abe Miessler
@Abe: Ganz rechts würde nicht verwendet - Sie müssen die Indexreihenfolge von links erfüllen. Fräulein, kann es nicht benutzen.
OMG Ponys
4
@Abe: Wenn Sie nach Adresse und Stadt gefragt haben, aber NICHT nach Bundesstaat - dann wird der Index verwendet. Mit anderen Worten, die Datenbank kann Teilindizes verwenden, um eine Anforderung zu erfüllen, solange sie in der Lage ist, von der linken Seite eines Index zu beginnen und sich bei der Verwendung der abgefragten Felder nach rechts zu bewegen. Wenn Sie jedoch mit Adresse und Bundesland, aber NICHT mit Stadt abgefragt haben, wird der Index möglicherweise weiterhin verwendet, er ist jedoch nicht so effizient, da jetzt nur noch der Adressteil des Index verwendet werden kann (b / c next is) Stadt und es wird nicht in der Abfrage verwendet).
JaredC
6

Alle anderen Antworten sind falsch.

Die Selektivität der einzelnen Spalten in einem zusammengesetzten Index spielt bei der Auswahl der Bestellung keine Rolle.

Hier ist der einfache Denkprozess: Ein Index ist effektiv die Verkettung der beteiligten Spalten.

Ausgehend von dieser Begründung besteht der einzige Unterschied darin, zwei "Zeichenfolgen" zu vergleichen, die sich früher und später in der Zeichenfolge unterscheiden. Dies ist ein winziger Teil der Gesamtkosten. Es gibt keinen "ersten Durchgang / zweiten Durchgang", wie in einer Antwort erwähnt.

Also, welche Reihenfolge sollte verwendet werden?

  1. Beginnen Sie mit den getesteten Spalten =in beliebiger Reihenfolge.
  2. Dann eine Bereichssäule anheften.

Zum Beispiel ist die sehr geringe Selektivität Säule muss zuerst kommt in diesen:

WHERE deleted = 0  AND  the_datetime > NOW() - INTERVAL 7 DAY
INDEX(deleted, the_datetime)

Wenn Sie die Reihenfolge im Index austauschen, wird dies völlig ignoriert deleted.

(Es gibt viel mehr Regeln für die Reihenfolge der Spalten.)

Rick James
quelle
Ist die negative Abstimmung, weil ich falsch liege? Oder weil ich eine starke Meinung habe? Oder etwas anderes?
Rick James
war nicht meine Ablehnung, aber gelöscht = 0 klingt für mich so, als wäre es keine geringe Selektivität? Ich stelle mir vor, es wäre die Mehrheit der Zeilen in der Tabelle.
Greg
@ Greg - Ich denke, das bedeutet "geringe Selektivität" - Das heißt, die Verwendung deletedhilft nicht viel beim Herausfiltern unerwünschter Zeilen. Hast du ein besseres Beispiel? (Das ist derjenige, der mir in den Sinn kam, als ich die Antwort schrieb.)
Rick James
Missverständnis meinerseits.
Greg
1
@ClickOk - Danke. Mein Kochbuch enthält einige grundlegende Informationen: mysql.rjweb.org/doc.php/index_cookbook_mysql
Rick James