Optimierung der Abfrage mit Bedingung - WHERE ID IN (SELECT ...)

20 Oct 2012 um 15:00 - MySQL/Datenbank

Die Optimierung der SQL-Abfragen kann ziemlich spannend sein. Heutzutage wird es immer populär zu argumentieren, dass die Optimierung der Architektur teurer sei als neue Hardware. So sucht man meistens nicht nach Problemursachen, sondern kauft z.B. dazu neuen Server etc. Aber früher oder später kommen die Probleme mit der Optimierung zurück.

Vor kurzem habe ich mich mit der SQL-Optimierung beschäftigt. An einer Stelle ging es um die Verbesserung der Geschwindigkeit für folgender Art von Abfragen:

 SELECT A.* FROM TABLE1 A WHERE A.ID IN (SELECT ID FROM TABLE2)

Die Abfragen wirken sehr natürlich und sind quasi Umformulierung der menschlichen Sprache: "Gib mir alle Einträge, die in anderer Tabelle vorkommen"

Diese Art von Abfragen laufen ziemlich gut, nur wenn es sich nur um wenige Datensätze handelt, aber ab einer Größe sinkt die Geschwindigkeit und plötzlich läuft es nicht mehr...

Man kann annehmen, dass die Unterabfrage von MySQL nur einmal ausgeführt wird. Die Realität sieht aber anders aus, die Abfrage wird wie folgt umgeschrieben:

 SELECT A.* FROM TABLE1 A WHERE EXISTS (SELECT 1 FROM TABLE2 B WHERE B.ID=A.ID)

Diese Optimierung von MySQL kann man mit Hilfe von EXPLAIN EXTENDED-Operator anschauen, für die genauere Erklärung kommt nach der Abfrage gleich SHOW WARNINGS:

 EXPLAIN EXTENDED SELECT A.* FROM TABLE1 A 
WHERE EXISTS (SELECT 1 FROM TABLE2 WHERE TABLE1.ID=TABLE2.ID);
SHOW WARNINGS;

So sieht man die Abfrage nach der Arbeit von SQL-Optimizator. Unerwartet, oder ;) Diese Vorgehensweise lässt uns die Problemstellen zu finden und zu sehen, wie die Abfrage tatsächlich ausgeführt wird.

Ok, wie optimiert man das? Die Unterabfrage wird mehrmals ausgeführt, deshalb kann man es so anpassen:

 SELECT A.* FROM TABLE1 A, (SELECT ID FROM TABLE2) B WHERE A.ID=B.ID

Schon besser, aber hier bekommen wir mehr Einträge als man braucht. Die IDs in Untertabelle (SELECT ...) können mehrmals vorkommen und zu jedem passenden Eintrag aus TABLE1 bekommt man alle möglichen aus (SELECT ...) Dann "simulieren" wir diese IN-Unterabfrage mit DISTINCT:

 SELECT A.* FROM TABLE1 A, (SELECT DISTINCT ID FROM TABLE2) B WHERE A.ID=B.ID

Viel Spaß bei der Entwicklung :)

Kommentare

Bisland keine Kommentare - sei der erste!


© 2008 Anton Pavlushko - Webentwicklung, Internetmarketing und Suchmaschinenoptimierung (SEO)

0.006415843963623 sec