Ich bin ein MySQL-Benutzer der alten Schule und habe immer eine Unterabfrage vorgezogen JOIN
. Aber heutzutage verwendet jeder eine Unterabfrage, und ich hasse es; Ich weiß nicht warum.
Mir fehlt das theoretische Wissen, um selbst zu beurteilen, ob es einen Unterschied gibt. Ist eine Unterabfrage so gut wie eine JOIN
und gibt es daher keinen Grund zur Sorge?
Antworten:
Entnommen aus dem MySQL-Handbuch ( 13.2.10.11 Umschreiben von Unterabfragen als Joins ):
Unterabfragen können also langsamer sein als
LEFT [OUTER] JOIN
, aber meiner Meinung nach ist ihre Stärke etwas besser lesbar .quelle
Join
undsub query
hat unterschiedliche Syntax, so dass Lesbarkeit wir nicht vergleichen können, beide haben eine höhere Lesbarkeit, solange Sie gut in SQL-Syntax sind. Leistung ist wichtiger.Unterabfragen sind der logisch korrekte Weg, um Probleme des Formulars "Fakten von A abrufen, abhängig von Fakten von B" zu lösen. In solchen Fällen ist es logischer, B in eine Unterabfrage zu stecken, als einen Join durchzuführen. In praktischer Hinsicht ist dies auch sicherer, da Sie nicht vorsichtig sein müssen, wenn Sie aufgrund mehrerer Spiele gegen B doppelte Fakten von A erhalten.
In der Praxis kommt die Antwort jedoch normalerweise auf die Leistung an. Einige Optimierer saugen Zitronen, wenn sie einen Join gegen eine Unterabfrage erhalten, und andere saugen Zitronen in die andere Richtung. Dies ist optimiererspezifisch, DBMS-version-spezifisch und abfragespezifisch.
Historisch gesehen gewinnen explizite Verknüpfungen normalerweise, daher ist die etablierte Weisheit, dass Verknüpfungen besser sind, aber Optimierer werden immer besser. Daher schreibe ich Abfragen lieber zuerst auf logisch kohärente Weise und restrukturiere sie dann, wenn Leistungsbeschränkungen dies rechtfertigen.
quelle
select custid from cust join bought using (custid) where price > 500
. Wenn ein Kunde mehrere teure Artikel gekauft hat, erhalten Sie Double-Ups. Um dies zu beheben ,select custid from cust where exists (select * from bought where custid = cust.custid and price > 500)
. Sie könntenselect distinct …
stattdessen verwenden, aber es ist oft mehr Arbeit, entweder für den Optimierer oder den Evaluator.In den meisten Fällen sind
JOIN
s schneller als Unterabfragen und es ist sehr selten, dass eine Unterabfrage schneller ist.In
JOIN
s kann RDBMS einen Ausführungsplan erstellen, der für Ihre Abfrage besser geeignet ist, und vorhersagen, welche Daten zur Verarbeitung geladen werden sollen, und Zeit sparen, im Gegensatz zu der Unterabfrage, bei der alle Abfragen ausgeführt und alle Daten für die Verarbeitung geladen werden .Das Gute an Unterabfragen ist, dass sie besser lesbar sind als
JOIN
s: Deshalb bevorzugen die meisten neuen SQL-Benutzer sie. es ist der einfache Weg; Aber wenn es um Leistung geht, sind JOINS in den meisten Fällen besser, obwohl sie auch nicht schwer zu lesen sind.quelle
select * from a where a.x = (select b.x form b where b.id = a.id)
im Vergleich zu einem Join extrem klein. Dies ist ein sehr spezifisches Problem, aber in einigen Fällen dauert es Stunden bis Minuten.Verwenden Sie EXPLAIN, um zu sehen, wie Ihre Datenbank die Abfrage für Ihre Daten ausführt. In dieser Antwort steckt ein riesiges "es kommt darauf an" ...
PostgreSQL kann eine Unterabfrage in einen Join oder einen Join in eine Unterabfrage umschreiben, wenn es glaubt, dass eine schneller als die andere ist. Es hängt alles von den Daten, Indizes, Korrelationen, Datenmengen, Abfragen usw. ab.
quelle
Im Jahr 2010 wäre ich dem Autor dieser Fragen beigetreten und hätte stark dafür gestimmt
JOIN
, aber mit viel mehr Erfahrung (insbesondere in MySQL) kann ich sagen: Ja, Unterabfragen können besser sein. Ich habe hier mehrere Antworten gelesen. Einige der angegebenen Unterabfragen sind schneller, aber es fehlte eine gute Erklärung. Ich hoffe, ich kann einem diese (sehr) späte Antwort geben:Lassen Sie mich zunächst das Wichtigste sagen: Es gibt verschiedene Formen von Unterabfragen
Und die zweite wichtige Aussage: Größe ist wichtig
Wenn Sie Unterabfragen verwenden, sollten Sie wissen, wie der DB-Server die Unterabfrage ausführt. Besonders wenn die Unterabfrage einmal oder für jede Zeile ausgewertet wird! Auf der anderen Seite kann ein moderner DB-Server viel optimieren. In einigen Fällen hilft eine Unterabfrage bei der Optimierung einer Abfrage, aber eine neuere Version des DB-Servers kann die Optimierung überflüssig machen.
Unterabfragen in Auswahlfeldern
Beachten Sie, dass für jede resultierende Zeile aus eine Unterabfrage ausgeführt wird
foo
.Vermeiden Sie dies wenn möglich; Dies kann Ihre Abfrage bei großen Datenmengen drastisch verlangsamen. Wenn die Unterabfrage jedoch keinen Verweis darauf
foo
hat, kann sie vom DB-Server als statischer Inhalt optimiert und nur einmal ausgewertet werden.Unterabfragen in der Where-Anweisung
Wenn Sie Glück haben, optimiert die DB dies intern in eine
JOIN
. Wenn nicht, wird Ihre Abfrage bei großen Datenmengen sehr, sehr langsam, da die Unterabfrage für jede Zeile ausgeführt wirdfoo
, nicht nur für die Ergebnisse wie beim Auswahltyp.Unterabfragen in der Join-Anweisung
Das ist interessant. Wir kombinieren
JOIN
mit einer Unterabfrage. Und hier bekommen wir die wahre Stärke von Unterabfragen. Stellen Sie sich einen Datensatz mit Millionen von Zeilen vor,wilco
aber nur wenigen unterschiedlichenme
. Anstatt sich gegen einen riesigen Tisch anzumelden, haben wir jetzt einen kleineren temporären Tisch, gegen den wir uns anmelden können. Dies kann je nach Datenbankgröße zu viel schnelleren Abfragen führen. Sie können den gleichen Effekt mitCREATE TEMPORARY TABLE ...
und erzielenINSERT INTO ... SELECT ...
, was möglicherweise zu einer besseren Lesbarkeit bei sehr komplexen Abfragen führt (Sie können jedoch Datensätze in einer wiederholbaren Leseisolationsstufe sperren).Verschachtelte Unterabfragen
Sie können Unterabfragen in mehreren Ebenen verschachteln. Dies kann bei großen Datenmengen hilfreich sein, wenn Sie die Ergebnisse gruppieren oder sortieren müssen. Normalerweise erstellt der DB-Server hierfür eine temporäre Tabelle, aber manchmal müssen Sie nicht die gesamte Tabelle sortieren, sondern nur die Ergebnismenge. Dies kann je nach Größe der Tabelle zu einer viel besseren Leistung führen.
Fazit
Unterabfragen sind kein Ersatz für a
JOIN
und Sie sollten sie nicht so verwenden (obwohl möglich). Meiner bescheidenen Meinung nach ist die korrekte Verwendung einer Unterabfrage die Verwendung als schneller Ersatz fürCREATE TEMPORARY TABLE ...
. Eine gute Unterabfrage reduziert ein Dataset auf eine Weise, die Sie in einerON
Anweisung von a nicht erreichen könnenJOIN
. Wenn eine Unterabfrage eines der Schlüsselwörter hatGROUP BY
oderDISTINCT
sich vorzugsweise nicht in den Auswahlfeldern oder in der where-Anweisung befindet, kann dies die Leistung erheblich verbessern.quelle
Sub-queries in the Join-statement
: (1) Das Generieren einer abgeleiteten Tabelle aus der Unterabfrage selbst kann sehr lange dauern. (2) Die resultierende abgeleitete Tabelle wird nicht indiziert. Diese beiden allein könnten die SQL erheblich verlangsamen.10
Datensätze reduzieren können , da kein Index vorhanden ist, bedeutet dies möglicherweise, dass beim Verbinden anderer Tabellen möglicherweise 9-mal mehr Datensätze als ohne temporäre Tabelle abgefragt werden. Übrigens hatte ich dieses Problem schon einmal mit meiner Datenbank (MySQL). In meinem Fall könnte die Verwendung von Unterabfragen inSELECT list
viel schneller sein.EXPLAIN
vor der Optimierung eine Abfrage verwenden. Mit dem altenset profiling=1
konnte man leicht erkennen, ob ein temporärer Tisch ein Engpass ist. Und selbst ein Index benötigt Verarbeitungszeit. B-Trees optimieren die Abfrage nach Datensätzen, aber eine Tabelle mit 10 Datensätzen kann viel schneller sein als ein Index für Millionen von Datensätzen. Dies hängt jedoch von mehreren Faktoren wie Feldgrößen und -typen ab.Um die beiden zuerst zu vergleichen, sollten Sie zunächst Abfragen mit Unterabfragen unterscheiden, um:
Für die erste Klasse von Abfragen sieht ein gutes RDBMS Verknüpfungen und Unterabfragen als gleichwertig und erzeugt dieselben Abfragepläne.
Heutzutage macht das sogar MySQL.
Manchmal ist dies jedoch nicht der Fall, aber dies bedeutet nicht, dass Joins immer gewinnen. Ich hatte Fälle, in denen Unterabfragen in MySQL die Leistung verbesserten. (Wenn beispielsweise etwas den MySQL-Planer daran hindert, die Kosten korrekt zu schätzen, und der Planer die Join-Variante und die Unterabfrage-Variante nicht als gleich ansieht, können Unterabfragen die Joins übertreffen, indem sie einen bestimmten Pfad erzwingen.)
Die Schlussfolgerung ist, dass Sie Ihre Abfragen sowohl für Join- als auch für Unterabfragevarianten testen sollten, wenn Sie sicher sein möchten, welche Variante eine bessere Leistung erbringt.
Für die zweite Klasse macht der Vergleich keinen Sinn, da diese Abfragen nicht mithilfe von Joins neu geschrieben werden können. In diesen Fällen sind Unterabfragen eine natürliche Methode, um die erforderlichen Aufgaben auszuführen, und Sie sollten sie nicht diskriminieren.
quelle
Ich denke, was in den zitierten Antworten unterbetont wurde, ist das Problem von Duplikaten und problematischen Ergebnissen, die sich aus bestimmten (Anwendungs-) Fällen ergeben können.
(obwohl Marcelo Cantos es erwähnt)
Ich werde das Beispiel aus Stanfords Lagunita-Kursen zu SQL zitieren.
Schülertisch
Tabelle anwenden
(Bewerbungen an bestimmten Universitäten und Hauptfächern)
Versuchen wir, die GPA-Ergebnisse für Studenten zu finden, die sich für ein
CS
Hauptfach beworben haben (unabhängig von der Universität).Verwenden einer Unterabfrage:
Der Durchschnittswert für diese Ergebnismenge ist:
Verwenden eines Joins:
Durchschnittswert für diese Ergebnismenge:
Es ist offensichtlich, dass der zweite Versuch in unserem Anwendungsfall zu irreführenden Ergebnissen führt, da für die Berechnung des Durchschnittswerts Duplikate gezählt werden. Es ist auch offensichtlich, dass die Verwendung von
distinct
mit der join-basierten Anweisung das Problem nicht beseitigt, da fälschlicherweise eines von drei Vorkommen der3.9
Punktzahl beibehalten wird. Der richtige Fall besteht darin, ZWEI (2) Vorkommen der3.9
Punktzahl zu berücksichtigen, vorausgesetzt , wir haben tatsächlich ZWEI (2) Schüler mit dieser Punktzahl, die unseren Abfragekriterien entsprechen.In einigen Fällen scheint eine Unterabfrage neben Leistungsproblemen der sicherste Weg zu sein.
quelle
In der MSDN-Dokumentation für SQL Server heißt es
Also, wenn Sie so etwas brauchen
Versuchen Sie stattdessen, join zu verwenden. In anderen Fällen macht es keinen Unterschied.
Ich sage: Das Erstellen von Funktionen für Unterabfragen beseitigt das Problem des Cluttters und ermöglicht es Ihnen, zusätzliche Logik für Unterabfragen zu implementieren. Ich empfehle daher, wann immer möglich Funktionen für Unterabfragen zu erstellen.
Unordnung im Code ist ein großes Problem, und die Industrie arbeitet seit Jahrzehnten daran, es zu vermeiden.
quelle
NOT EXISTS
. ANOT EXISTS
gewinntLEFT OUTER JOIN
aus verschiedenen Gründen gegen a: Leistung, Ausfallsicherheit (bei nulierbaren Spalten) und Lesbarkeit. sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-joinFühren Sie eine sehr große Datenbank von einem alten Mambo-CMS aus:
0 Sekunden
~ 3 Sekunden
Eine EXPLAIN zeigt, dass sie genau die gleiche Anzahl von Zeilen untersuchen, aber eine dauert 3 Sekunden und eine ist fast augenblicklich. Moral der Geschichte? Wenn Leistung wichtig ist (wann nicht?), Probieren Sie es auf verschiedene Arten aus und finden Sie heraus, welche am schnellsten ist.
Und...
0 Sekunden
Wieder die gleichen Ergebnisse, die gleiche Anzahl der untersuchten Zeilen. Ich vermute, dass DISTINCT mos_content.catid viel länger braucht, um herauszufinden, als DISTINCT mos_categories.id.
quelle
id
und nicht socatid
? Der Versuch, meine Datenbankzugriffe zu optimieren, und Ihre Erkenntnisse könnten helfen.Nach meiner Beobachtung wie in zwei Fällen funktioniert der Join schnell, wenn eine Tabelle weniger als 100.000 Datensätze enthält.
Wenn eine Tabelle jedoch mehr als 100.000 Datensätze enthält, ist eine Unterabfrage das beste Ergebnis.
Ich habe eine Tabelle mit 500.000 Datensätzen, die ich unter der Abfrage erstellt habe, und die Ergebniszeit ist wie folgt
quelle
Unterabfragen werden im Allgemeinen verwendet, um eine einzelne Zeile als atomaren Wert zurückzugeben. Sie können jedoch verwendet werden, um Werte mit mehreren Zeilen mit dem Schlüsselwort IN zu vergleichen. Sie sind an nahezu jedem wichtigen Punkt in einer SQL-Anweisung zulässig, einschließlich der Zielliste, der WHERE-Klausel usw. Eine einfache Unterabfrage kann als Suchbedingung verwendet werden. Zum Beispiel zwischen zwei Tabellen:
Beachten Sie, dass für die Verwendung eines Normalwertoperators für die Ergebnisse einer Unterabfrage nur ein Feld zurückgegeben werden muss. Wenn Sie prüfen möchten, ob ein einzelner Wert in einer Reihe anderer Werte vorhanden ist, verwenden Sie IN:
Dies unterscheidet sich offensichtlich von einem LEFT-JOIN, bei dem Sie nur Inhalte aus Tabelle A und B verknüpfen möchten, auch wenn die Verknüpfungsbedingung keinen passenden Datensatz in Tabelle B usw. findet.
Wenn Sie sich nur Sorgen um die Geschwindigkeit machen, müssen Sie Ihre Datenbank überprüfen und eine gute Abfrage schreiben, um festzustellen, ob es einen signifikanten Leistungsunterschied gibt.
quelle
MySQL-Version: 5.5.28-0ubuntu0.12.04.2-log
Ich hatte auch den Eindruck, dass JOIN in MySQL immer besser ist als eine Unterabfrage, aber EXPLAIN ist ein besserer Weg, um ein Urteil zu fällen. Hier ist ein Beispiel, in dem Unterabfragen besser funktionieren als JOINs.
Hier ist meine Anfrage mit 3 Unterabfragen:
EXPLAIN zeigt:
Die gleiche Abfrage mit JOINs lautet:
und die Ausgabe ist:
Ein Vergleich der
rows
Spalte zeigt den Unterschied und die Abfrage mit JOINs wird verwendetUsing temporary; Using filesort
.Wenn ich beide Abfragen ausführe, ist die erste in 0,02 Sekunden erledigt, die zweite wird auch nach 1 Minute nicht abgeschlossen, daher hat EXPLAIN diese Abfragen richtig erklärt.
Wenn ich den INNER JOIN nicht auf dem
list_tag
Tisch habe, dh wenn ich entferneab der ersten Abfrage und entsprechend:
Ab der zweiten Abfrage gibt EXPLAIN für beide Abfragen die gleiche Anzahl von Zeilen zurück, und beide Abfragen werden gleich schnell ausgeführt.
quelle
Unterabfragen können Aggregationsfunktionen im laufenden Betrieb berechnen. ZB Finden Sie den Mindestpreis des Buches und erhalten Sie alle Bücher, die mit diesem Preis verkauft werden. 1) Verwenden von Unterabfragen:
2) Verwenden von JOINs
quelle
GROUP BY
s mit unterschiedlichen Tabellen: stackoverflow.com/questions/11415284/… Unterabfragen scheinen streng allgemeiner zu sein. Siehe auch den MySQL-Mann: dev.mysql.com/doc/refman/5.7/en/optimizing-subqueries.html | dev.mysql.com/doc/refman/5.7/de/rewriting-subqueries.htmlEinige Leute sagen, "einige RDBMS können eine Unterabfrage in einen Join oder einen Join in eine Unterabfrage umschreiben, wenn sie glauben , dass eine schneller als die andere ist.", Aber diese Aussage gilt für einfache Fälle, sicherlich nicht für komplizierte Abfragen mit Unterabfragen, die tatsächlich a verursachen Leistungsprobleme.
quelle
Der Unterschied wird nur sichtbar, wenn die zweite Verbindungstabelle wesentlich mehr Daten enthält als die Primärtabelle. Ich hatte eine Erfahrung wie unten ...
Wir hatten eine Benutzertabelle mit einhunderttausend Einträgen und deren Mitgliedschaftsdaten (Freundschaft) von ungefähr dreihunderttausend Einträgen. Es war eine Join-Anweisung, um Freunde und ihre Daten aufzunehmen, aber mit großer Verzögerung. Aber es funktionierte gut, wenn die Mitgliedschaftstabelle nur eine geringe Datenmenge enthielt. Nachdem wir es geändert hatten, um eine Unterabfrage zu verwenden, funktionierte es einwandfrei.
In der Zwischenzeit arbeiten die Join-Abfragen jedoch mit anderen Tabellen, die weniger Einträge als die Primärtabelle haben.
Daher denke ich, dass die Join- und Sub-Query-Anweisungen einwandfrei funktionieren und von den Daten und der Situation abhängen.
quelle
Heutzutage können viele Datenbankanbieter Unterabfragen und Verknüpfungen optimieren. Sie müssen Ihre Anfrage also einfach mit EXPLAIN untersuchen und feststellen, welche schneller ist. Wenn es keinen großen Unterschied in der Leistung gibt, bevorzuge ich die Verwendung von Unterabfragen, da diese einfach und leichter zu verstehen sind.
quelle
Ich denke nur an das gleiche Problem, aber ich verwende die Unterabfrage im FROM-Teil. Ich muss eine Verbindung herstellen und von großen Tabellen abfragen, die "Slave" -Tabelle hat 28 Millionen Datensätze, aber das Ergebnis sind nur 128, also kleine Ergebnisse, große Datenmengen! Ich benutze die MAX () Funktion darauf.
Erstens verwende ich LEFT JOIN, weil ich denke, dass dies der richtige Weg ist, das MySQL kann sich optimieren usw. Zum zweiten Mal schreibe ich nur zum Testen um, um eine Unterauswahl gegen das JOIN zu treffen.
LEFT JOIN-Laufzeit: 1,12 s SUB-SELECT-Laufzeit: 0,06 s
18 mal schneller die Unterauswahl als der Join! Nur im Chokito Adv. Die Unterauswahl sieht schrecklich aus, aber das Ergebnis ...
quelle
Wenn Sie Ihre Abfrage mit join beschleunigen möchten:
Verwenden Sie für "inner join / join" nicht die where-Bedingung, sondern die Bedingung "ON". Z.B:
Verwenden Sie für "Links / Rechts-Verknüpfung" nicht die Option "EIN", da bei Verwendung der Links / Rechts-Verknüpfung alle Zeilen für eine Tabelle abgerufen werden. Daher wird die Verwendung in "Ein" nicht verwendet. Versuchen Sie also, die Bedingung "Wo" zu verwenden
quelle