Gibt es einen Ausführungsunterschied zwischen einer JOIN-Bedingung und einer WHERE-Bedingung?

17

Gibt es einen Leistungsunterschied zwischen diesen beiden Beispielabfragen?

Abfrage 1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

Abfrage 2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

Beachten Sie, dass der einzige Unterschied in der Platzierung der Zusatzbedingung besteht. Der erste verwendet eine WHEREKlausel und der zweite fügt der ONKlausel die Bedingung hinzu .

Wenn ich diese Abfragen auf meinem Teradata-System ausführe, sind die EXPLAIN-Pläne identisch und der JOIN-Schritt zeigt die jeweils zusätzliche Bedingung an. Bei dieser SO-Frage zu MySQL schlug eine der Antworten jedoch vor, dass der zweite Stil bevorzugt wird, da die WHEREVerarbeitung nach dem Herstellen der Verknüpfungen erfolgt.

Gibt es eine allgemeine Regel, nach der Abfragen wie diese codiert werden müssen? Ich vermute, es muss plattformabhängig sein, da es offensichtlich keinen Unterschied für meine Datenbank macht, aber vielleicht ist das nur eine Funktion von Teradata. Und wenn es ist plattformabhängig, würde ich sehr gerne ein paar Dokumentation Referenzen zu erhalten; Ich weiß wirklich nicht, wonach ich suchen soll.

BellevueBob
quelle
9
Es ist plattformabhängig, da es davon abhängt, wie der RDBMSes-Optimierer mit dem Parsen und der Optimierung umgeht.
Philᵀᴹ
8
Und diese Antwort in der verknüpften Frage verdient mehrere Ablehnungen. Selbst MySQLs primitiver Optimierer würde verstehen, dass diese einfachen Abfragen äquivalent sind und dass "die WHERE-Klausel ausgewertet wird, nachdem alle Verknüpfungen vorgenommen wurden" nur auf einer logischen Ebene und nicht in der tatsächlichen Ausführung zutrifft.
ypercubeᵀᴹ
1
Nicht wirklich ein Duplikat; Diese Frage und die Antworten verglichen die "implizite" mit der "expliziten" JOIN-Syntax. Ich frage speziell nach zusätzlichen Beitrittsbedingungen.
BellevueBob
Ich werde es nicht wagen, eine Antwort einzureichen, da ich es zuvor versucht habe und viele Abwertungen erzielt habe. Wenn es viele Verknüpfungen gibt, habe ich die Erfahrung gemacht, dass das Heraufstufen der Bedingung in die Verknüpfung zu einem besseren Abfrageplan geführt hat (früh gefiltert). Immer noch die gleichen Ergebnisse.
Paparazzo

Antworten:

14

Gemäß Kapitel 9 (Parser und Optimierer), Seite 172 des Buches Grundlegendes zu MySQL-Interna von Sasha Pachev

Grundlegendes zu MySQL-Interna

Hier ist die Aufteilung der Auswertung einer Abfrage nach folgenden Aufgaben:

  • Bestimmen Sie, mit welchen Schlüsseln die Datensätze aus Tabellen abgerufen werden können, und wählen Sie für jede Tabelle den besten aus.
  • Entscheiden Sie für jede Tabelle, ob ein Tabellenscan besser ist als das Lesen auf einem Schlüssel. Wenn viele Datensätze mit dem Schlüsselwert übereinstimmen, werden die Vorteile des Schlüssels verringert und der Tabellenscan wird schneller.
  • Bestimmen Sie die Reihenfolge, in der Tabellen verknüpft werden sollen, wenn mehr als eine Tabelle in der Abfrage vorhanden ist.
  • Schreiben Sie die WHERE-Klauseln neu, um toten Code zu beseitigen, die unnötigen Berechnungen zu reduzieren und die Einschränkungen nach Möglichkeit zu ändern, um die Verwendung von Schlüsseln zu ermöglichen.
  • Beseitigen Sie nicht verwendete Tabellen aus dem Join.
  • Bestimmen Sie, ob Schlüssel für ORDER BYund verwendet werden können GROUP BY.
  • Versuchen Sie, Unterabfragen zu vereinfachen und festzustellen, inwieweit ihre Ergebnisse zwischengespeichert werden können.
  • Ansichten zusammenführen (Ansichtsreferenz als Makro erweitern)

Auf derselben Seite steht:

In der Terminologie des MySQL-Optimierers besteht jede Abfrage aus einer Reihe von Joins. Der Begriff Join wird hier breiter verwendet als in SQL-Befehlen. Eine Abfrage für nur eine Tabelle ist eine entartete Verknüpfung. Während wir normalerweise nicht daran denken, Datensätze aus einer Tabelle als Join zu lesen, funktionieren dieselben Strukturen und Algorithmen wie bei herkömmlichen Joins perfekt, um die Abfrage mit nur einer Tabelle aufzulösen.

EPILOG

Aufgrund der vorhandenen Schlüssel, der Datenmenge und des Ausdrucks der Abfrage können MySQL-Verknüpfungen manchmal zu unserem eigenen Wohl (oder um zu uns zurückzukehren) beitragen und Ergebnisse erzielen, die wir nicht erwartet haben und die wir nicht schnell erklären können.

Ich habe schon früher über diese Kuriosität geschrieben

weil der MySQL Query Optimizer bestimmte Schlüssel während der Auswertung der Abfrage verwerfen könnte.

@ Phils Kommentar hilf mir, diese Antwort zu posten (+1 für @ Phils Kommentar)

@ ypercubes Kommentar (+1 auch für diesen) ist eine kompakte Version meines Posts, da MySQLs Query Optimizer primitiv ist. Leider muss es sein, da es sich um externe Speicher-Engines handelt.

FAZIT

Was Ihre eigentliche Frage betrifft, würde das MySQL-Abfrageoptimierungsprogramm die Leistungsmetriken jeder Abfrage ermitteln, wenn diese erledigt ist

  • Reihen zählen
  • Schlüssel auswählen
  • Massieren von intermittierenden Ergebnissätzen
  • Oh ja, mache den eigentlichen JOIN

Wahrscheinlich müssten Sie die Ausführungsreihenfolge erzwingen, indem Sie die Abfrage neu schreiben (refactoring)

Hier ist die erste Abfrage, die Sie gegeben haben

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

Versuchen Sie es neu zu schreiben, um zuerst das WHERE auszuwerten

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

Das würde definitiv den EXPLAIN-Plan ändern. Es könnte zu besseren oder schlechteren Ergebnissen führen.

Ich habe einmal eine Frage in StackOverflow beantwortet, in der ich diese Technik angewendet habe. Das EXPLAIN war horrend, aber die Aufführung war Dynamit. Es funktionierte nur, weil die richtigen Indizes vorhanden waren und LIMIT in einer Unterabfrage verwendet wurde .

Ähnlich wie bei den Aktienkursen gelten bei Abfragen und dem Versuch, sie auszudrücken, Beschränkungen, die Ergebnisse können variieren und die Wertentwicklung in der Vergangenheit ist kein Hinweis auf zukünftige Ergebnisse.

RolandoMySQLDBA
quelle
2
+1 für die detaillierten MySQL-spezifischen Informationen und vor allem dafür, dass ich den Unterschied zwischen "Epilog" und "Fazit" herausgefunden habe!
BellevueBob
In meinem Beitrag ist der Epilog ein Unterfazit.
RolandoMySQLDBA
6
@Rolando: Sie können eine hinzufügen Aftermath über Verbesserungen an den Optimierer in neuestem MariaDB (5.3 und 5.5) Versionen und in dem kürzlich veröffentlichten Haupt MySQL (5.6) Version. Was ein Umschreiben unnötig machen könnte.
ypercubeᵀᴹ
1

Für Oracle haben wir, da mySQL eine lange Beschreibung hatte, zwei Möglichkeiten, den Optimierer wirksam einzusetzen.

Erstens ist die regelbasierte Optimierung (oder RBO). Oracle hat 15 festgelegte Regeln, denen jede Abfrage, die es analysiert, in einer festgelegten Reihenfolge zu folgen versucht. Wenn aus Regel 1 keine optimierte Abfrage generiert werden kann, wird mit Regel 2 fortgefahren, bis Regel 15 erreicht wird.

Weitere Informationen: https://docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

Diese betreffen Oracle RDBMS-Kernel ab 11.1, die nicht in Cost Based Optimizer (auch bekannt als CBO) konvertiert wurden. Oracle 11.2 und höher erfordern das CBO-Optimierungsprogramm, können jedoch bestimmte SQL-IDs zur Optimierung in der alten RBO-Methode zwingen, wenn der Benutzer dies wünscht.

Das CBO für Oracle 11.1+ erstellt stattdessen mehrere Ausführungspläne für dieselbe SQL-ID und führt denjenigen mit den geringsten erwarteten Gesamtkosten aus. Es nutzt einen Großteil der Logik von RBO, analysiert jedoch Tabellenstatistiken, um dynamische Ausführungsplankosten für jeden Vorgang zu erstellen, den die DB ausführen muss, um dem Endbenutzer ihre Daten bereitzustellen. Das Ausführen vollständiger Tabellensuchen an sehr großen Tabellen ist sehr kostspielig. Das Ausführen vollständiger Tabellenscans für eine Tabelle mit 10 Zeilen ist günstig. In der RBO wurden diese als gleichberechtigt angesehen.

Weitere Informationen: https://oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

Für Ihr spezielles Abfragebeispiel: Oracle würde die Informationen wahrscheinlich analysieren, um unterschiedliche Ausführungspläne zu erstellen, und daher ist einer technisch besser als der andere. Dies kann jedoch ein minimaler Unterschied sein. Oracle RBO und CBO möchten eine Abfrage 1 mehr, da sie bei einem Join unter weniger Bedingungen ausgeführt wird und dann eine bestimmte Spalte aus der temporären Tabelle herausfiltert, die sie bei dem Join erstellt hat.

JB-Learner
quelle
1

Wenn Sie zwei Abfragen haben und diese für gleichwertig halten, kann Folgendes passieren:

  1. Beide Abfragen haben den gleichen Ausführungsplan. Das ist in Ordnung und das erwarten wir auch. Hoffen wir, dass dies der optimale Ausführungsplan für die Abfrage ist.
  2. Es gibt verschiedene Ausführungspläne. Wir haben hier zwei Unterfälle.

    2.1 Die Abfragen haben unterschiedliche Ausführungspläne, aber beide Pläne sind gleich gut. Das ist auch gut so. Es ist nicht erforderlich, dass für äquivalente Abfragen derselbe Plan generiert wird. Die Leistung sollte aber gleich sein. Und wieder hoffen wir, dass es das bestmögliche ist.

    2.2 Die Abfragen haben unterschiedliche Ausführungspläne und ein Plan ist besser als der andere. Wieder haben wir Unterfälle:

    2.2.1 Die Pläne sind unterschiedlich, da die Abfragen nicht gleichwertig sind. Prüfen Sie daher sorgfältig, ob sie wirklich gleichwertig sind. In Ihrem Fall sind sie wirklich gleichwertig.

    2.2.2 Die Pläne sind unterschiedlich, aber die Abfragen sind gleichwertig. Dies bedeutet, dass der Optimierer nicht ausreichend ausgereift ist. In einer perfekten Welt mit perfekten Optimierern sollte dies nicht passieren. Also ja, es ist plattformabhängig und Sie müssen plattformspezifische Dokumente studieren, um herauszufinden, warum dies geschieht.

    2.2.3 Die Pläne sind unterschiedlich, die Abfragen sind äquivalent, die Datenbanksoftware hat einen Fehler.

miracle173
quelle