JOIN-Schlüsselwort verwenden oder nicht

45

Die folgenden SQL-Abfragen sind identisch:

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

Und mit Sicherheit ergeben sich auf jedem DBMS, das ich je ausprobiert habe, die gleichen Abfragepläne.

Aber ab und zu lese oder höre ich die Meinung, dass einer definitiv besser ist als der andere. Natürlich werden diese Behauptungen niemals mit einer Erklärung belegt.

Wo ich arbeite, scheint die zweite Version von den meisten anderen Entwicklern bevorzugt zu werden, und so tendiere ich auch zu diesem Stil, um Überraschungen zu minimieren. Aber in meinem Herzen denke ich wirklich an das Erste (da ich es ursprünglich so gelernt habe).

Ist eine dieser Formen objektiv besser als die andere? Wenn nicht, was wären die Gründe, eins übereinander zu verwenden?

SingleNegationElimination
quelle
1
Warum nicht ein Profil erstellen und den Rest von uns über das Ergebnis informieren? Im Allgemeinen überwiegt die Leistung die Stilvorlieben.
Demian Brecht
3
"Führen Sie auf jedem DBMS, das ich jemals ausprobiert habe, zu denselben Abfrageplänen." Leider sind sie die gleiche Abfrage.
SingleNegationElimination
Ah .. Habe das verpasst :)
Demian Brecht
2
"Subjektiv" bedeutet nicht "was ist Ihre Meinung". Ich habe das zu bearbeitende Art der Kriterien angelegt in der Meet FAQ .
Aaronaught
Ich tendiere auch zu diesem Stil, um Überraschungen so gering wie möglich zu halten. Ich glaube, Sie haben gerade Ihre eigene Frage beantwortet. Überraschungen sind schlecht.
Pieter B

Antworten:

60

Ich finde, dass die zweite Form besser ist. Das mag daran liegen, dass ich es so gelernt habe, ich gebe zu, aber ich habe einen konkreten Grund - die Trennung von Bedenken. Das Einfügen der Felder, die Sie zum Verknüpfen der Tabellen verwenden, in die where-Klausel kann zu Problemen beim Verständnis von Abfragen führen.

Nehmen Sie zum Beispiel die folgende Abfrage:

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

Die obige Abfrage enthält Tabellenverknüpfungsbedingungen und tatsächliche Geschäftslogikbedingungen, die alle in einem einzigen Bereich zusammengefasst sind. Bei einer großen Abfrage kann dies sehr schwer zu verstehen sein.

Nehmen Sie jedoch jetzt diesen Code:

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

In diesem Fall wird alles, was mit den Tabellen zu tun hat oder in welcher Beziehung sie zueinander stehen, von der from-Klausel isoliert, während sich die eigentliche Geschäftslogik für die Einschränkung von Abfragen in der where-Klausel befindet. Ich denke, das ist gerade bei größeren Anfragen viel verständlicher.

Dustin Wilhelmi
quelle
Dies ist die einzig sinnvolle Möglichkeit, wenn Sie an zwei Tabellen vorbeigekommen sind oder eine Kombination aus Links-, Rechts- und Voll-Joins benötigen.
Aglassman
5
+1 Für "Separation of Concerns"
39

Die Join-Syntax hat 1992 die alte Komma-Syntax abgelöst. Derzeit gibt es keinen Grund, jemals Code mit der Komma-Syntax zu schreiben. Sie gewinnen nichts und haben einige Probleme, die Sie mit der expliziten Syntax einfach nicht haben.

Wenn Sie kompliziertere Abfragen erhalten, ist es in erster Linie sehr einfach, eine versehentliche Querverbindung durchzuführen, indem eine where-Bedingung fehlt. Dies kann durch die explizite Join-Syntax verhindert werden, da ein Syntaxfehler auftritt.

Wenn Sie einen Cross-Join beabsichtigen, wird dies durch die explizite Join-Syntax verdeutlicht, während in der impliziten Syntax angenommen wird, dass jemand, der die Wartung ausführt, vergessen hat, die where-Klausel hinzuzufügen.

Dann gibt es das Problem der Left- und Right-Joins, die zumindest in einigen DBs, die die implizite Syntax verwenden, problematisch sind. Sie sind in SQL Server veraltet und liefern tatsächlich keine korrekten Ergebnisse, auch nicht in den älteren Versionen. Keine Abfrage, die eine äußere Verknüpfung benötigt, sollte die implizite Syntax in SQL Server enthalten.

Außerdem habe ich hier und auf anderen Websites Fragen gesehen, bei denen beim Mischen der impliziten und expliziten Verknüpfungen (z. B. beim Hinzufügen einer linken Verknüpfung) falsche Ergebnisse aufgetreten sind. Daher ist es keine gute Idee, diese zu mischen.

Schließlich verstehen viele Leute, die implizite Verknüpfungen verwenden, Verknüpfungen nicht. Dies ist ein kritisches Verständnis, das Sie benötigen, um eine Datenbank effektiv abfragen zu können.

HLGEM
quelle
Vielen Dank für die Erklärung. Als mir beigebracht wurde, wurde uns beide Syntax gezeigt, aber der Unterschied wurde nicht erklärt. Ich habe es manchmal geschafft, Abfragen mit fehlenden Positionen zu erstellen, was offen gesagt die Anzahl der Schreibvorgänge erhöht hätte, wenn ich mich erst einmal explizit angemeldet hätte.
awiebe
8

Ha. Ich habe gerade eine mögliche Antwort auf meine eigene Frage gefunden, als ich mir die Dokumentation für PostgreSQL angesehen habe . Um zusammenzufassen, was auf dieser Seite erklärt wird, ist die resultierende Abfrage immer noch dieselbe, aber die Anzahl der Pläne, die das Optimierungsprogramm berücksichtigen muss, wächst exponentiell mit der Anzahl der Joins.

Nach ungefähr sechs solchen Verknüpfungen ist die Anzahl so groß, dass die Zeit zum Planen der Abfrage möglicherweise spürbar ist. Nach ungefähr zehn wechselt das Optimierungsprogramm von einer umfassenden Suche nach Plänen zu einer probabilistischen Suche und gelangt möglicherweise nicht zum optimalen Plan .

Durch Festlegen eines Laufzeitparameters können Sie den Planer anweisen, explizit erwähnte Innen- und Kreuzverknüpfungen anders als implizite Verknüpfungen zu behandeln, sie an die oberste Stelle des Plans zu zwingen und andere Optionen nicht zu untersuchen.

Es ist zu beachten, dass das Standardverhalten in beiden Fällen dasselbe ist und dass das Abrufen alternativer Pläne das Wissen über die Interna der DBMS und die Besonderheiten der betreffenden Tabellen erfordert, um ein anderes Ergebnis zu erzielen

SingleNegationElimination
quelle
2
Sie haben diese Dokumente jedoch leicht missverstanden. Erstens gibt es tatsächlich drei Schwellenwerte. Man feuert den GEQO ab, wie Sie betont haben; Die anderen beiden (von und Zusammenbruchgrenzen der Verbindung) führen dazu, dass der Planer die entsprechenden Indizes auswählt, anstatt die Verknüpfungsreihenfolge neu zu organisieren. Zweitens und genauso wichtig ist, dass die Abfragen beim Parsen neu geschrieben werden. Dies führt dazu, dass die erste der Beispielabfragen in genau denselben Abfragebaum wie die zweite analysiert wird - die Schwellenwerte geben PG dann an, ob versucht werden soll, die Verknüpfungen neu zu ordnen oder nicht.
Denis de Bernardy
8

Nun, hier ist die Ansicht der Mengenlehre:

Wenn Sie zwei (oder mehr) Tabellennamen durch ein Komma trennen, ist das kartesische Produkt das, was Sie beabsichtigen. Jede Zeile der "linken" Tabelle wird mit der der rechten Tabelle "abgeglichen" (verkettet).

Wenn Sie nun etwas in die where-Klausel schreiben, ist das so, als würden Sie dieser Verkettung eine Bedingung hinzufügen, die angibt, welche Zeilen mit welchen Zeilen verkettet werden sollen.

Dies ist eigentlich das "Verbinden" der Zeilen :) und daher das Join-Schlüsselwort, das eine besser lesbare Syntax bietet und verständlicher ist, dass Sie "in der Tat" einige gemeinsame Werte verbinden möchten. Ähnlich wie @Dustin oben erklärt hat.

Jetzt ist jedes DBMS intelligent, dh es berechnet nicht erst das kartesische Produkt und filtert dann die Daten heraus (extrem verschwenderisch), sondern basiert auf der Abfragestruktur. Das Einzige, woran ich denken kann, ist, wenn Sie ihn bitten, beizutreten, ist es, als ob Sie die Beitrittsaktivität explizit machen und wahrscheinlich dabei helfen, den Code schneller auszuführen (um wie viel? Sie müssen ihn profilieren und sehen), aber in der In einem durch Kommas getrennten Fall braucht es einige Zeit, um die optimale Strategie zu finden. Ich kann mich irren, aber ich mache nur eine fundierte Vermutung, wie man es codieren würde ...

PhD
quelle
5

Ich denke, es ist im Allgemeinen besser, JOIN-Anweisungen für diesen Fall zu verwenden.

Wenn in Zukunft eine Situation auftritt, in der die Anweisung von INNER JOIN in OUTER JOIN geändert werden muss, ist dies mit der zweiten Anweisung viel einfacher.

Britt Wescott
quelle
3

Jedes RDBMS wird sie in Bezug auf die Ausführung gleich machen. Es kommt darauf an, ob man lesbarer und ausdrucksvoller ist.

Verwenden Sie JOIN, damit klar ist, was Join-Matching ist und was Auswahl ist, wie in:

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

gegen

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

Letzterer Fall macht sofort klar, welche Join-Bedingung und welches Auswahlkriterium vorliegt.

Andy Lester
quelle
1

Ich habe die beiden Ergebnisse nur einmal in einer anderen Optimierungsreihe gesehen, und wenn der Speicher belegt ist, war dies in ms-sql2k bei einer wirklich haarigen Abfrage. In diesem einen Beispiel führte die alte Form, die mit * = verwendet wurde, zu einer etwa viermal schnelleren Leistung. Niemand, einschließlich unserer Microsoft-Techniker, konnte jemals erklären, warum. Die MS-Leute bezeichneten es als Fehler. Ich habe es nie wieder gesehen.

Da die meisten RDBMS klug genug sind, nicht die vollen Kartesier zu machen, ist der größte Grund, warum ich daran denken kann, sie nicht zu verwenden (abgesehen davon, dass sie abgeschrieben wird), dass die meisten Leute unter 30-35, mit denen ich gearbeitet habe, die noch nie gesehen haben alte Form vor und gehen schrecklich verloren, wenn sie darauf stoßen.

Rechnung
quelle
Natürlich lieferte diese Left-Join-Syntax niemals zuverlässig die richtigen Ergebnisse (siehe BOL für SQL Server 2000). Selbst wenn sie schneller wäre, hätte ich sie ersetzt.
HLGEM
Das habe ich nie erlebt, und die Suche mit dem Sternchen endet nie gut. Haben Sie ein Beispiel?
Bill
-1

Der alte Stil ist veraltet, Sie sollten ihn nicht verwenden.

Es sollte nicht einmal einen Streit geben, über den man besser ist oder nicht. Neuer Code sollte nicht die alte Syntax verwenden.

Pieter B
quelle
Ich denke, diese Antwort fügt nichts hinzu, ohne zu sagen, warum sie veraltet war und nicht verwendet werden sollte.
RemcoGerlich
1
@RemcoGerlich, warum es veraltet ist, wird hier nicht diskutiert. Hier wird diskutiert, ob die alte oder die neue Syntax verwendet werden soll. Ob das eine besser ist als das andere oder nicht, ist umstritten: Sie sollten keine alte Syntax verwenden. Die Warum- Frage ist eine andere Diskussion. (Eine, die vor 20 Jahren besiedelt wurde.)
Pieter B
-4

Ein Grund für die prägnantere Syntax ist, dass sie prägnanter ist. Wenn Sie sich also damit auskennen, ist sie leichter zu lesen. Ich betrachte den ausführlichen Fall als vergleichbar mit dem Ausschreiben von Arithmetik in COBOL, z. B. MULTIPLY A BY B GIVING C.

John Bickers
quelle
Downvoter: Gibt es irgendetwas Falsches in dieser Antwort, oder waren sie nur "mit Ihnen nicht einverstanden" Downvotes?
Adam Libuša