Benötige ich separate Indizes für jeden Abfragetyp oder funktioniert ein mehrspaltiger Index?

22

Ich kenne die Antwort auf diese Frage schon ein wenig, aber ich habe immer das Gefühl, dass ich mehr zu diesem Thema tun muss.

Mein grundlegendes Verständnis ist, dass im Allgemeinen ein einziger Index, der nur alle Felder enthält, nach denen Sie möglicherweise zu einem bestimmten Zeitpunkt fragen / sortieren, wahrscheinlich nicht nützlich ist, aber ich habe diese Art von Dingen gesehen. Wie in, dachte jemand, "Nun, wenn wir all diese Dinge einfach in einen Index stellen, kann die Datenbank damit herausfinden, was sie benötigt", ohne jemals einen Ausführungsplan für einige der tatsächlich ausgeführten Abfragen gesehen zu haben.

Stellen Sie sich einen Tisch so vor:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

Ich könnte einen einzigen Index einschließlich der sehen name, customerIdund dateCreatedFelder.

Ich verstehe jedoch, dass ein solcher Index nicht in einer Abfrage verwendet wird, wie zum Beispiel:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Für eine solche Abfrage scheint mir eine bessere Idee ein Index zu sein, der die Felder customerIdund enthält dateCreated, wobei das customerIdFeld 'first' ist. Auf diese Weise wird ein Index erstellt, in dem die Daten so organisiert sind, dass diese Abfrage schnell das findet, was sie benötigt - in der Reihenfolge, in der sie benötigt.

Eine andere Sache, die ich vielleicht so häufig wie die erste sehe, sind einzelne Indizes für jedes Feld; so, je eine auf name, customerIdund dateCreatedFelder.

Im Gegensatz zum ersten Beispiel scheint mir diese Art der Anordnung manchmal zumindest teilweise nützlich zu sein; Der Ausführungsplan der Abfrage zeigt möglicherweise, dass zumindest der Index für die customerIdAuswahl der Datensätze verwendet wird, nicht jedoch der Index für das dateCreatedFeld, um sie zu sortieren.


Ich weiß, dass dies eine weit gefasste Frage ist, da die spezifische Antwort auf eine bestimmte Abfrage in einer bestimmten Menge von Tabellen normalerweise darin besteht, zu sehen, was der Ausführungsplan vorschreibt, und ansonsten die Besonderheiten der Tabelle (n) und Abfragen zu berücksichtigen Konto. Ich weiß auch, dass dies davon abhängt, wie oft eine Abfrage ausgeführt wird, und nicht davon, ob ein bestimmter Index dafür verwaltet wird.

Aber ich nehme an, was ich frage, ist ein allgemeiner "Ausgangspunkt" für Indizes. Ist die Idee, bestimmte Indizes für bestimmte, häufig abgerufene Abfragen und die Felder in den WHERE- oder ORDER BY-Klauseln zu haben, sinnvoll?

Andrew Barber
quelle

Antworten:

27

Sie haben Recht, dass Ihre Beispielabfrage diesen Index nicht verwenden würde.

Der Abfrageplaner wird die Verwendung eines Index in Betracht ziehen, wenn:

  • Alle darin enthaltenen Felder werden in der Abfrage referenziert
  • Einige der Felder, die am Anfang beginnen, werden referenziert

Indizes, die mit einem von der Abfrage nicht verwendeten Feld beginnen, können nicht verwendet werden.

Also für dein Beispiel:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

es würde Indizes berücksichtigen wie:

[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]

aber nicht:

[name], [customerId], [dateCreated]

Wenn es beides findet [customerId]und [customerId], [dateCreated], [name]seine Entscheidung, eines dem anderen vorzuziehen, von den Indexstatistiken abhängt, die von Schätzungen des Datengleichgewichts in den Feldern abhängen. Wenn [customerId], [dateCreated]definiert, sollte dies den beiden anderen vorgezogen werden, es sei denn, Sie geben einen bestimmten Index-Hinweis auf das Gegenteil.

Meiner Erfahrung nach ist es auch nicht ungewöhnlich, dass für jedes Feld ein Index definiert wird. Dies ist jedoch selten optimal, da die zusätzliche Verwaltung, die zum Aktualisieren der Indizes beim Einfügen / Aktualisieren erforderlich ist, und der zusätzliche Speicherplatz, der zum Speichern dieser Indizes erforderlich ist, zur Hälfte verschwendet wird Sie werden vielleicht nie benutzt - aber wenn Ihre Datenbank nicht überlastet ist, stinkt die Leistung auch mit den überschüssigen Indizes nicht schlecht.

Spezifische Indizes für häufige Abfragen, die ansonsten aufgrund von Tabellen- oder Index-Scans langsam wären, sind im Allgemeinen eine gute Idee. Übertreiben Sie dies jedoch nicht, da Sie möglicherweise ein Leistungsproblem gegen ein anderes austauschen. Wenn Sie [customerId], [dateCreated]beispielsweise einen Index definieren , denken Sie daran, dass der Abfrageplaner diesen für Abfragen verwenden kann, für die nur ein Index [customerId]vorhanden ist. Während die Verwendung von just [customerId]geringfügig effizienter ist als die Verwendung des zusammengesetzten Index, kann dies dadurch gemindert werden, dass zwei Indizes anstelle von einem um den Speicherplatz im RAM konkurrieren (wenn jedoch Ihr gesamtes normales Arbeitsset problemlos in den RAM passt, ist dies möglicherweise kein zusätzlicher Speicherwettbewerb ein Problem).

David Spillett
quelle
+1; gute Infos, vor allem der Erinnerung (die ich oft vergessen!) , dass der Planer kann eine Verbindung Index manchmal verwenden , wenn es nur das erste Feld (n) von ihm für eine Abfrage benötigt.
Andrew Barber
6

Ja, um Ihre ursprüngliche Frage zu beantworten, müssen Indizes für die Abfragen erstellt werden , nicht nur für die Tabelle . Die Reihenfolge der Felder im Index ist von entscheidender Bedeutung. Es ist schwieriger, einen einzelnen Index so zu gestalten, dass er für mehrere Abfragen optimal ist, und Sie müssen Kompromisse eingehen.

In Bezug auf Ihren zweiten Punkt ist es ärgerlich, dass eine Reihe von Indizes für einzelne einzelne Felder vorhanden sind. Ich sehe es die ganze Zeit in meiner Umgebung und es ist normalerweise eine rote Fahne für mich, dass das Entwicklungsteam nicht mit einem DBA zusammengearbeitet hat, um die richtigen Indizes zu entwerfen.

Meine Strategie zum Entwerfen von Indizes besteht darin, Folgendes zu indizieren:

  • In WHERE verwendete Felder (in der Reihenfolge der Selektivität)
  • In ORDER BY verwendete Felder
  • Fügen Sie bei Bedarf weitere Felder hinzu, um einen Deckungsindex zu erstellen

Also für dein Beispiel:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Ich würde wahrscheinlich einen Index für (CustomerID, dateCreated) INCLUDE (id, name) entwerfen. Dieser Deckungsindex bedeutet, dass die Abfrage niemals die ursprüngliche Tabelle erreichen muss, was die Leistung erheblich verbessert.

Dieses Beispiel ist jedoch fast zu einfach. Ein naiver Index für nur (CustomerID) würde fast genauso gut abschneiden (vorausgesetzt, jeder Kunde hat nur einen einzigen Mitarbeiter, so dass nur ein einziges Lesezeichen für die Tabelle erforderlich ist). Es kann auch nützlich sein, einen Clustered- Index für (CustomerID, ID) zu erstellen , abhängig davon, welche anderen Abfragen für die Tabelle ausgeführt werden.

BradC
quelle
+1 für "Indizes müssen sich an den Abfragen und nicht nur an der Tabelle orientieren" und an der restlichen Antwort, beispielsweise an der Feststellung, dass das Beispiel sehr einfach ist.
Andrew Barber