Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Beeinflusst die Reihenfolge der Felder in einer WHERE-Klausel die Leistung in MySQL?

SQL wurde als deklarative Sprache konzipiert, nicht als prozedurale. Der Abfrageoptimierer sollte das also nicht Berücksichtigen Sie die Reihenfolge der Prädikate der where-Klauseln, um zu bestimmen, wie sie anzuwenden sind.

Ich werde die folgende Diskussion eines SQL-Abfrageoptimierers wahrscheinlich zu stark vereinfachen. Ich habe vor einem Jahr in diese Richtung geschrieben (es hat jede Menge Spaß gemacht!). Wenn Sie wirklich in die moderne Abfrageoptimierung eintauchen möchten, lesen Sie Dan Tows SQL-Tuning , von O'Reilly.

In einem einfachen SQL-Abfrageoptimierer wird die SQL-Anweisung zuerst in einen Baum der relationalen Algebra kompiliert Operationen. Diese Operationen verwenden jeweils eine oder mehrere Tabellen als Eingabe und erzeugen eine andere Tabelle als Ausgabe. Scannen ist ein sequenzieller Scan, der eine Tabelle aus der Datenbank einliest. Sortieren erzeugt eine sortierte Tabelle. Auswählen erzeugt eine Tabelle, deren Zeilen gemäß einer Auswahlbedingung aus einer anderen Tabelle ausgewählt werden. Projekt erzeugt eine Tabelle mit nur bestimmten Spalten einer anderen Tabelle. Kreuzprodukt nimmt zwei Tabellen und erzeugt eine Ausgabetabelle, die aus allen denkbaren Paaren ihrer Zeilen besteht.

Verwirrenderweise wird die SQL-SELECT-Klausel in ein relationales Algebra-Projekt kompiliert , während sich die WHERE-Klausel in eine relationale Algebra Select verwandelt . Die FROM-Klausel wird zu einem oder mehreren Joins , wobei jeweils zwei Tabellen aufgenommen und eine Tabelle ausgegeben werden. Es gibt andere Operationen der relationalen Algebra, die Mengenvereinigung, Schnittmenge, Differenz und Zugehörigkeit beinhalten, aber halten wir es einfach.

Dieser Baum muss wirklich optimiert werden. Wenn Sie beispielsweise Folgendes haben:

select E.name, D.name 
from Employee E, Department D 
where E.id = 123456 and E.dept_id = D.dept_id

Bei 5.000 Mitarbeitern in 500 Abteilungen führt die Ausführung eines nicht optimierten Baums blindlings zu allen möglichen Kombinationen aus einem Mitarbeiter und einer Abteilung (ein Kreuzprodukt). ) und dann Auswählen nur die eine Kombination, die benötigt wurde. Der Scan des Mitarbeiters erstellt eine Tabelle mit 5.000 Datensätzen, den Scan of Department erstellt eine Tabelle mit 500 Datensätzen, das Kreuzprodukt dieser beiden Tabellen ergibt eine Tabelle mit 2.500.000 Datensätzen und die Select auf E.id nimmt diese 2.500.000-Datensatz-Tabelle und verwirft alle bis auf einen, den gewünschten Datensatz.

[Echte Abfrageprozessoren werden natürlich versuchen, nicht alle diese Zwischentabellen im Speicher zu materialisieren.]

Der Abfrageoptimierer geht also durch den Baum und wendet verschiedene Optimierungen an. Eine besteht darin, jedes Select aufzubrechen in eine Kette von Selects , eine für jede der ursprünglichen Select 's Top-Level-Bedingungen, die Ones and-ed zusammen. (Das nennt man "konjunktive Normalform".) Dann die einzelnen kleineren Selects werden im Baum verschoben und mit anderen Operationen der relationalen Algebra zu effizienteren zusammengeführt.

Im obigen Beispiel drückt der Optimierer zuerst auf Select auf E.id =123456 unterhalb des teuren Kreuzprodukts Betrieb. Gemeint ist damit das Kreuzprodukt erzeugt nur 500 Zeilen (eine für jede Kombination aus diesem Mitarbeiter und einer Abteilung). Dann die oberste Ebene Auswählen for E.dept_id =D.dept_id filtert die 499 unerwünschten Zeilen heraus. Nicht schlecht.

Wenn es einen Index für das ID-Feld des Mitarbeiters gibt, kann der Optimierer den Scan kombinieren des Mitarbeiters mit Auswählen auf E.id =123456, um einen schnellen Index Lookup zu bilden . Dies bedeutet, dass statt 5.000 nur eine Employee-Zeile von der Festplatte in den Arbeitsspeicher gelesen wird. Es geht aufwärts.

Die letzte große Optimierung ist die Auswahl auf E.dept_id =D.dept_id und kombiniere es mit dem Kreuzprodukt . Dadurch wird es zu einem Equijoin der relationalen Algebra Betrieb. Das bringt an sich nicht viel. Aber wenn es einen Index auf Department.dept_id gibt, dann der sequenzielle Scan auf niedrigerer Ebene der Abteilung, die den Equijoin füttert kann in einen sehr schnellen Index Lookup umgewandelt werden des Abteilungsdatensatzes unseres einen Mitarbeiters.

Geringere Optimierungen beinhalten das Pushen von Project Betrieb herunter. Wenn die oberste Ebene Ihrer Abfrage nur E.name und D.name benötigt und die Bedingungen E.id, E.dept_id und D.dept_id benötigen, dann wird der Scan Operationen müssen keine Zwischentabellen mit allen anderen Spalten erstellen, was Platz während der Abfrageausführung spart. Wir haben eine furchtbar langsame Abfrage in zwei Indexsuchen und nicht viel mehr verwandelt.

Um der ursprünglichen Frage näher zu kommen, nehmen wir an, Sie haben:

select E.name 
from Employee E 
where E.age > 21 and E.state = 'Delaware'

Der nicht optimierte relationale Algebra-Baum würde bei seiner Ausführung die 5.000 Mitarbeiter scannen und beispielsweise die 126 Mitarbeiter in Delaware produzieren, die älter als 21 Jahre sind. Der Abfrageoptimierer hat auch eine ungefähre Vorstellung von den Werten in der Datenbank. Es könnte wissen, dass die E.state-Spalte die 14 Staaten enthält, in denen das Unternehmen Standorte hat, und etwas über die E.age-Verteilungen. Zuerst sieht es also, ob eines der Felder indiziert ist. Wenn E.state dies ist, ist es sinnvoll, diesen Index zu verwenden, um nur die kleine Anzahl von Mitarbeitern herauszusuchen, die der Abfrageprozessor basierend auf seinen zuletzt berechneten Statistiken in Delaware vermutet. Wenn es nur E.age ist, entscheidet der Abfrageprozessor wahrscheinlich, dass es sich nicht lohnt, da 96 % aller Mitarbeiter 22 Jahre und älter sind. Wenn also E.state indiziert ist, unterbricht unser Abfrageprozessor das Select und fügt E.state ='Delaware' mit Scan zusammen um daraus einen viel effizienteren Index-Scan zu machen .

Nehmen wir in diesem Beispiel an, dass es keine Indizes für E.state und E.age gibt. Die kombinierte Auswählen Der Vorgang erfolgt nach dem sequentiellen "Scan" von Employee. Macht es einen Unterschied welche Bedingung im Select ist erstmal fertig? Wahrscheinlich nicht viel. Der Abfrageprozessor kann sie in der ursprünglichen Reihenfolge in der SQL-Anweisung belassen, oder er könnte etwas ausgefeilter sein und den erwarteten Aufwand berücksichtigen. Anhand der Statistik würde es wieder feststellen, dass die Bedingung E.state ='Delaware' hochselektiver sein sollte, also würde es die Bedingungen umkehren und dies zuerst tun, sodass es nur 126 E.age> 21 Vergleiche anstelle von 5.000 gibt . Oder es könnte erkennen, dass String-Gleichheitsvergleiche viel teurer sind als Integer-Vergleiche und die Reihenfolge in Ruhe lassen.

Auf jeden Fall ist dies alles sehr komplex und Ihre syntaktische Bedingungsreihenfolge wird wahrscheinlich keinen Unterschied machen. Ich würde mir darüber keine Gedanken machen, es sei denn, Sie haben ein echtes Leistungsproblem und Ihr Datenbankanbieter verwendet die Bedingungsreihenfolge als Hinweis.