Was tut MySQL selbst für die Performance von SELECT-Abfragen?

WHERE-Klauseln sind eigentlich die einfachste Sache, wenn man mit SQL-Abfragen arbeitet. Doch viele Abfragen lassen sich noch weiter vereinfachen.
Da der Einsatz der WHERE-Bedingungen entscheidend für den daraus folgenden Einsatz von Indizes und somit der Performance ist, verarbeitet MySQL nach dem Absenden einer Abfrage diese und verändert sie, ohne die Logik zu beeinflussen. Dafür wird die Abfrage aber performanter. Ich möchte heute mal aufzeigen, was MySQL im Hintergrund so alles anstellt, damit Abfragen möglichst schnell behandelt werden.

MySQL führt Optimierungen durch den so genannten Query Optimizer durch. Zuerst ist da das Entfernen unnötiger Klammern, die man ja gern mal setzt, weil man die logischen Einheiten verdeutlichen will oder auch nicht hundertprozentig parat hat, ob OR oder AND Priorität hat.
Anschließend kommt das sogenannte Folding (Konstanten-Faltung). Darunter versteht man das Einsetzen von Konstanten, wenn sich diese auf die gleiche Spalte innerhalb der Query mehrmals beziehen. Aus dem Folding folgt das Entfernen von unnötigen Bedingungen.
Hier mal am Beispiel diese 3 Sachen gezeigt:

SELECT * 
FROM tabelle
WHERE ((a AND b) AND c OR (((a AND b) AND (c AND d))))
 
// unnötige Klammern entfernt
SELECT * 
FROM tabelle
WHERE a AND b AND c OR a AND b AND c AND d
 
...
WHERE (a<b AND b=c) AND a=5
 
// Konstanten-Folding
...
WHERE b>5 AND b=c AND a=5
 
 
...
WHERE (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
 
// Bedingungsentfernung
WHERE B=5 OR B=6

Außerdem werden mehrmals verwendete Konstanten-Ausdrücke in einer Query nur einmal ausgewertet.
Wenn COUNT(*) ohne Bedingung aufgerufen wird, kann MySQL gleich auf die Tabelleninformationen zugreifen und somit sehr schnell ein Ergebnis zurückliefern.
Früherkennung ungültiger Konstanten: Manche Werte können einfach nicht vorkommen, z.B. negative Werte in einer UNSIGNED-Spalte, NULL-Werte in einer NOT-NULL-Spalte oder Werte, die außerhalb des Definitionsbereichs liegen (zu große Zahlen, zu lange Strings). MySQL erkennt das sehr schnell und liefert ein leeres Ergebnis zurück ohne ewig andere Aufgaben der Query auszuführen, nur um irgendwann mal festzustellen, dass das ja so gar nicht geht.

HAVING und WHERE werden vereinigt, wenn keine GROUP-Funktion genutzt wird.
Alle Konstanten-Tabellen werden zuerst gelesen, vor jeder anderen Tabelle in der Anfrage, wobei eine Konstantentabelle eine Tabelle mit 0 oder einer Zeile sein kann (recht selten) oder eine Tabelle, die bei einer WHERE-Klausel (oder auch bei einer JOIN-Klausel) auf einen UNIQUE- oder PRIMARY-Index abgefragt wird (häufiger).

Die beste Join-Kombination, um Tabellen zu verknüpfen, wird gefunden, wenn man alle Möglichkeiten probiert. Wenn alle Spalten in ORDER BY und in GROUP BY aus derselben Tabelle stammen, wird diese Tabelle vorzugsweise vorn hingestellt, wenn verknüpft wird.
Jeder Tabellen-Index wird abgefragt und der beste Index, der weniger als 30% der Zeilen überspannt, wird benutzt. Wenn ein solcher Index nicht gefunden werden kann, ist einTabellenscan (Full-Table-Scan) schneller und wird deshalb durchgeführt (deshalb immer per EXPLAIN überprüfen, ob Indizes genutzt werden).
In einigen Fällen kann MySQL Zeilen vom Index lesen, ohne überhaupt in der Daten-Datei nachzuschlagen. Wenn alle Spalten, die vom Index benutzt werden, numerisch sind, wird nur der Index-Baum benutzt, um die Anfrage aufzulösen.

Beim Einsatz von DISTINCT werden alle zu selektierenden Spalten in die GROUP BY-Menge hinzugefügt. Wird DISTINCT mit ORDER BY benutzt, ist oft eine temporäre Tabelle nötig.
Wird DISTINCT mit LIMIT verwendet, stoppt MySQL die Ausführung, sobald es die in LIMIT angegebene Zahl von eindeutigen Datensätzen gefunden hat.
Wenn Sie nicht Spalten aus allen benutzten Tabellen verwenden, hält MySQL mit dem Scannen der nicht benutzten Tabellen an, sobald er die erste Übereinstimmung gefunden hat.

SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.a=t2.a;

Im Beispiel wird angenommen, dass t1 vor t2 benutzt wird (überprüfen Sie das mit EXPLAIN). In diesem Fall hört MySQL auf, von t2 zu lesen (für diese bestimmte Zeile in t1), sobald die erste Zeile in t2 gefunden wurde.

Ich hoffe ich konnte etwas Licht ins Dunkel bringen. MySQL führt nämlich keineswegs genau das aus, was sie ihm vorwerfen. Query Optimizing ist das A und O im Kampf um Performance der unterschiedlichen Datenbank-Systeme.

Jan hat 152 Beiträge geschrieben

3 Kommentare zu “Was tut MySQL selbst für die Performance von SELECT-Abfragen?

  1. Pingback: oliver @ blogging

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>