Frage

Refactoring ich ein langsamer Abschnitt einer Anwendung, die wir von einem anderen Unternehmen geerbt einen inneren verwenden statt einer Unterabfrage wie

beitreten
where id in (select id from ... )

Die umstrukturierte Abfrage läuft über 100x schneller. (~ 50 Sekunden bis ~ 0.3) ich eine Verbesserung erwartet, aber kann jemand erklären, warum es so drastisch war? Die verwendeten Säulen in der where-Klausel wurden alle indiziert. Ist SQL die Abfrage in der Where-Klausel ausführen einmal pro Zeile, oder was?

Aktualisieren - Erklären Ergebnisse:

Der Unterschied ist im zweiten Teil des "where id in ()" Abfrage -

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

vs 1 indizierte Zeile mit dem Join:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index
War es hilfreich?

Lösung

A „korrelierte Unterabfrage“ (das heißt, eine, in der die in dem Zustand aus den Zeilen der Abfrage enthält, erhalten auf Werten abhängt) einmal für jede Zeile ausgeführt wird. Eine nicht-korrelierten Unterabfrage (ein, in der der in dem Zustand der Abfrage enthält, unabhängig ist) wird ausgeführt, einmal am Anfang. Die SQL-Engine macht diese Unterscheidung automatisch.

Aber, ja, erklären-Plan wird Ihnen die schmutzigen Details.

Andere Tipps

Sie führen die Unterabfrage einmal für jede Zeile , während der Verbindung geschieht auf Indizes.

Hier ist ein Beispiel dafür, wie Unterabfragen in MySQL 6.0 ausgewertet werden.

Der neue Optimierer wird diese Art von Unterabfragen umwandeln in beitritt.

Führen Sie das erklären-Plan auf jeder Version, es wird Ihnen sagen, warum.

, bevor die Abfragen für die Daten-Set ausführen werden sie durch einen Abfrageoptimierer gesetzt werden, versucht der Optimierer die Abfrage in einer solchen Art und Weise zu organisieren, dass es so schnell eingestellt, wie viele Tupel (Zeilen) aus dem Ergebnis entfernen können, wie sie können. Oft, wenn Sie Unterabfragen (besonders schlechte) die Tupel verwenden, können nicht aus der Ergebnismenge zurückgeschnitten werden, bis die äußere Abfrage zu laufen beginnt.

Mit der aus der Abfrage seines schwer zu sagen, zu sehen, was über das Original so schlecht war, aber meine Vermutung wäre es war etwas, das der Optimierer einfach nicht viel besser machen könnte. ‚Erklären‘ Laufen zeigen Ihnen die Optimizern Methode, um die Daten abzurufen.

In der Regel ist es das Ergebnis der Optimierer in der Lage, um herauszufinden, nicht, dass die Unterabfrage als Join ausgeführt werden kann, in diesem Fall ist es die Unterabfrage für jeden Datensatz in der Tabelle führt eher dann die Tabelle in der Unterabfrage der Tabelle verbinden Sie abfragen. Einige der „enterprisey“ Datenbank sind dies besser, aber sie vermissen es noch manchmal.

Diese Frage ist etwas allgemein, so ist hier eine allgemeine Antwort:

Grundsätzlich Abfragen länger dauern, wenn MySQL Tonnen Reihen hat zu sortieren.

Tun Sie dies:

Ausführen eines auf jedem der Abfragen ERKLäREN (die JOIN'ed eine, dann die Subqueried eins), und posten die Ergebnisse hier.

Ich denke, den Unterschied in der MySQL Interpretation dieser Abfragen zu sehen, würde eine Lernerfahrung für jeden etwas dabei sein.

Die where Unterabfrage 1 Abfrage für jede zurückgegebene Zeile laufen hat. Die innere Verknüpfung nur 1 Abfrage auszuführen hat.

Sehen Sie sich die Abfrage-Plan für jede Abfrage.

Wo in und Join Regel implementiert werden, um den gleichen Ausführungsplan verwenden, so Regel gibt es Null Speed-up zwischen ihnen ändert.

Optimizer hat einen sehr guten Job nicht machen. Normalerweise können sie ohne Unterschied transformiert werden und der Optimierer kann dies tun.

Die Unterabfrage wurde wahrscheinlich eine "Full-Table-Scan" ausgeführt wird. Mit anderen Worten, nicht den Index und die Rückkehr zu vielen Zeilen, die die Wo von der Hauptabfrage zum Ausfiltern wurden benötigen.

Nur eine Vermutung ohne Details natürlich, aber das ist die allgemeine Situation.

Mit einer Unterabfrage, müssen Sie die zweite SELECT für jedes Ergebnis erneut auszuführen, und jede Ausführung liefert typischerweise 1 Zeile.

Mit einem Join, gibt die zweite SELECT viel mehr Zeilen, aber man muss es nur einmal auszuführen. Der Vorteil ist, dass Sie jetzt auf den Ergebnissen kommen kann, und die Beziehungen verbinden ist, was eine Datenbank auf, gut sein soll. Zum Beispiel, vielleicht kann das Optimierungsprogramm vor Ort, wie jetzt besser die Vorteile eines Index zu nehmen.

Es ist nicht so sehr die Unterabfrage als die Klausel IN, obwohl zumindest von Oracle SQL-Engine verbindet sich bei der Gründung und extrem schnell ausgeführt werden.

aus dem Referenzhandbuch Taken ( 14.2.10.11 Umschreiben von Unterabfragen als verbindet ):

  

A LEFT [OUTER] JOIN kann als eine gleichwertige Unterabfrage schneller sein, da der Server könnte in der Lage sein, zu optimieren es besser eine Tatsache, die allein nicht spezifisch für MySQL Server ist.

So können Subqueries langsamer als LEFT [OUTER] beitritt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top