MySQL hat bekannte Probleme mit der Optimierung von Abfragen mit korrelierten Unterabfragen oder Unterauswahlen. Bis Version 5.6.5 materialisiert es keine Unterabfragen, es materialisiert jedoch eine abgeleitete Tabelle, die in einem Join verwendet wird.
Im Wesentlichen bedeutet dies, dass, wenn Sie einen Join verwenden, das erste Mal, wenn die Unterabfrage angetroffen wird, MySQL Folgendes ausführt:
SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1
Und halten Sie die Ergebnisse in einer temporären Tabelle (die gehasht wird, um die Suche zu beschleunigen), dann für jeden Wert in myTable
Es wird in der temporären Tabelle nachgesehen, ob der Code vorhanden ist.
Allerdings seit wann Sie IN
verwenden Die Unterabfrage wird nicht materialisiert und wie folgt umgeschrieben:
SELECT t1.code1, t1.code2
FROM myTable t1
WHERE EXISTS
( SELECT t2.code1
FROM myTable t2
WHERE t2.Code1 = t1.Code1
GROUP BY t2.code1
HAVING COUNT(t2.code1) > 1
)
Das heißt für jeden code
in myTable
, wird die Unterabfrage erneut ausgeführt. Wenn Ihre äußere Abfrage sehr eng ist, ist dies in Ordnung, da es effizienter ist, die Unterabfrage nur wenige Male auszuführen, als sie für alle Werte auszuführen und die Ergebnisse in einer temporären Tabelle zu speichern. Wenn Ihre äußere Abfrage jedoch breit ist, führt dies zu Ergebnissen in der inneren Abfrage, die viele Male ausgeführt wird, und hier tritt der Leistungsunterschied ins Spiel.
Anstatt die Unterabfrage ca. 30.000 Mal auszuführen, führen Sie sie also für Ihre Zeilenanzahl einmal aus und suchen dann ca. 30.000 Zeilen in einer temporären Hash-Tabelle mit nur 400 Zeilen nach. Dies würde einen so drastischen Leistungsunterschied erklären.
Dieser Artikel in der Online-Dokumentation erklärt die Optimierung von Unterabfragen viel ausführlicher.