Bedingung innerhalb von JOIN oder WHERE

191

Gibt es einen Unterschied (Leistung, Best Practice usw.) zwischen dem Einfügen einer Bedingung in die JOIN-Klausel und der WHERE-Klausel?

Beispielsweise...

-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'

-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'

Welches bevorzugen Sie (und vielleicht warum)?

Steve Dignan
quelle
4
Haben Sie die beiden Abfragen ausgeführt? Haben Sie die Ausführungspläne überprüft, die durch die beiden Abfragen generiert wurden? Was hast du beobachtet?
S.Lott
21
@ S.Lott, diese Abfrage dient nur zu Beispielzwecken. Ich frage mich nur "allgemein", welche Methode die bevorzugte ist - wenn überhaupt.
Steve Dignan
1
@Steve Dignan: Sie sollten dies mit Beispieldaten vergleichen und sich die Abfragepläne ansehen. Die Antwort wird sehr, sehr klar sein. Und - Bonus - Sie haben einen Code, den Sie wiederverwenden können, wenn komplexere Situationen auftreten.
S.Lott
1
Ich würde die Bedingung persönlich in die JOIN-Klausel aufnehmen, wenn die Bedingung die Beziehung beschreibt. Allgemeine Bedingungen, die nur die Ergebnismenge filtern, werden dann in den WHERE-Teil verschoben. ZBFROM Orders JOIN OrderParties ON Orders.Id = OrderParties.Order AND OrderParties.Type = 'Recipient' WHERE Orders.Status = 'Canceled'
Glutexo

Antworten:

153

Die relationale Algebra ermöglicht die Austauschbarkeit der Prädikate in der WHEREKlausel und der INNER JOIN, sodass selbst bei INNER JOINAbfragen mit WHEREKlauseln die Prädikate vom Optimierer neu angeordnet werden können, sodass sie möglicherweise bereits während des JOINProzesses ausgeschlossen werden.

Ich empfehle Ihnen, die Abfragen so gut wie möglich zu schreiben.

Manchmal beinhaltet dies das INNER JOINrelativ "unvollständige" und das Einfügen einiger Kriterien in WHEREdie Liste, um die Liste der Filterkriterien einfacher zu pflegen.

Zum Beispiel anstelle von:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Schreiben:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

Aber es kommt natürlich darauf an.

Cade Roux
quelle
7
Es geht nicht nur um saubere Abfragen oder Lesbarkeit, sondern auch um Leistung. Durch das Einfügen von Join-Bedingungen wird die Leistung für große Datenmengen mit ordnungsgemäß indizierten Tabellen verbessert.
Shahdat
1
Ich führe nur monatliche Verkaufsberichte aus, die 5-6 Tabellen mit einigen Millionen Datensätzen verbinden. Perf verbessert sich um 30% - SQL Server 2012
Shahdat
2
@Shahdat Wenn Sie einen so signifikanten Leistungsunterschied feststellen, dass Ihre Filterbedingungen von der where-Klausel in den inneren Join verschoben werden, müssen Sie diese Ausführungspläne veröffentlichen.
Cade Roux
4
@Cade Ich habe die Ausführungspläne untersucht - beide Szenarien zeigen die gleichen Kosten. Ich führe die Abfragen mehrmals aus. Beide scheinen ungefähr die gleiche Zeit in Anspruch zu nehmen. Zuvor habe ich die Abfragen in der Produktion ausgeführt und dabei erhebliche Leistungsunterschiede festgestellt, da die Datenbank von Live-Benutzern verwendet wurde. Entschuldigung für diese Verwirrung.
Shahdat
4
Diese Antwort ist richtig für INNER JOINs, aber nicht für Links / Rechts-Joins.
SOTN
121

Bei inneren Verknüpfungen habe ich keinen wirklichen Unterschied festgestellt (aber wie bei jeder Leistungsoptimierung müssen Sie unter Ihren Bedingungen eine Überprüfung Ihrer Datenbank durchführen).

Wo Sie die Bedingung setzen, macht jedoch einen großen Unterschied, ob Sie linke oder rechte Verknüpfungen verwenden. Betrachten Sie zum Beispiel diese beiden Abfragen:

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'

Mit dem ersten werden nur die Datensätze angezeigt, deren Bestellung später als am 15. Mai 2009 datiert wurde. Dadurch wird der linke Join in einen inneren Join konvertiert. Die zweite gibt diese Aufzeichnungen sowie alle Kunden ohne Bestellungen. Die Ergebnismenge ist sehr unterschiedlich, je nachdem, wo Sie die Bedingung setzen. (Wählen Sie *, wenn Sie dies beispielsweise nur zu Zwecken verwenden möchten, natürlich nicht im Produktionscode.) Die Ausnahme ist, wenn Sie nur die Datensätze in einer Tabelle anzeigen möchten, nicht jedoch in der anderen. Dann verwenden Sie die where-Klausel für die Bedingung, nicht den Join.

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null
HLGEM
quelle
Vielen Dank für die Erklärung mit Beispielen
Rennish Joseph
1
"So wird die linke Verknüpfung in eine innere Verknüpfung umgewandelt". Wie? Können Sie etwas näher darauf eingehen?
user1451111
@ user1451111 Erfahren Sie, was LEFT / RIGHT JOIN zurückgibt: INNER JOIN-Zeilen plus nicht übereinstimmende linke / rechte Tabellenzeilen, die um NULL-Werte erweitert wurden. FULL JOIN gibt INNER JOIN-Zeilen zurück. UNION ALL nicht übereinstimmende linke und rechte Tabellenzeilen, die um NULL erweitert wurden. Immer wissen, welchen INNER JOIN Sie als Teil eines OUTER JOIN möchten. Ein WHERE oder ON, bei dem eine möglicherweise NULL-erweiterte Spalte nicht NULL sein muss, nachdem OUTER JOIN ON alle durch NULL erweiterten Zeilen entfernt hat, dh nur INNER JOIN-Zeilen belässt, dh "OUTER JOIN in INNER JOIN umwandelt".
philipxy
1
@ user1451111 oder einfacher ausgedrückt: A left join BIst jede Zeile von A mit jeder übereinstimmenden Zeile von B verbunden ? Wenn B keine übereinstimmende Zeile hat, haben die A-Spalten einen Wert, aber jede Spalte von B in dieser Zeile wird als NULL-Wert angezeigt. Wenn Sie geschrieben haben, haben where B.somecolumn = ‘somevalue’Sie eine NULL (B.somecolumn), die mit 'somevalue' verglichen wird. Alles, was mit NULL verglichen wird, ist falsch, sodass alle Ihre Zeilen, in denen es keine übereinstimmende B-Zeile für die A-Zeile gibt, eliminiert werden und die Ergebnisse, die Sie erhalten, die gleichen sind, die ein INNER JOIN liefern würde, daher ist der äußere Join ein innerer geworden
Caius Jard
Ja, ich habe überprüft, ob die Ergebnisse für Folgendes gleich sind: SELECT Funds.id, Prospects.id FROM fundsInner Join-Interessenten auf (spects.id = Funds.lead_id und Prospects.is_manual = 'Nein') und SELECT Funds.id, Prospects.id FROM fundsLeft Schließen Sie sich potenziellen Kunden an unter (spects.id = funds.lead_id), wobeispects.is_manual = 'no'
Rohit Dhiman
25

Die meisten RDBMS-Produkte optimieren beide Abfragen identisch. In "SQL Performance Tuning" von Peter Gulutzan und Trudy Pelzer haben sie mehrere RDBMS-Marken getestet und keinen Leistungsunterschied festgestellt.

Ich bevorzuge es, Join-Bedingungen von Abfrageeinschränkungsbedingungen getrennt zu halten.

Wenn Sie OUTER JOINmanchmal verwenden, müssen Bedingungen in die Join-Klausel eingefügt werden.

Bill Karwin
quelle
1
Ich stimme Ihnen zu, dass es syntaktisch sauberer ist, und ich muss mich auf Ihr Wissen über dieses Buch und Ihr sehr hohes Ansehen verlassen, aber ich kann mir 4 Abfragen in der letzten Woche mit sehr unterschiedlichen Ausführungsplänen, CPU-Zeiten und logischen Lesevorgängen vorstellen Ich bin umgezogen, wo Prädikate zum Join sind.
März 75
2
Sie haben nach Best Practices gefragt. Sobald Sie testen, wie eine bestimmte RDBMS-Implementierung funktioniert, haben andere Leute den richtigen Rat gegeben: Benchmark.
Bill Karwin
12

WHERE wird nach dem JOIN gefiltert.

Filtern Sie nach JOIN, um zu verhindern, dass während des JOIN-Prozesses Zeilen hinzugefügt werden.

TheTXI
quelle
10
Semantisch werden sie während des INNER JOIN-Prozesses verhindert, aber der Optimierer kann INNER JOIN- und WHERE-Prädikate nach Belieben neu anordnen, sodass der Optimierer sie später ausschließen kann, wenn er dies wünscht.
Cade Roux
1
Cade Roux: Richtig. Oft ist das, was Sie in SQL schreiben, nicht das, was Ihnen der Optimierer gibt, wenn alles gesagt und getan ist. Ich würde dann annehmen, dass dies in einer Welt der
Alltheorie
Ich mag diese Erklärung des Zustands in derON
Robert Rocha
3

Ich bevorzuge JOIN, um vollständige Tabellen / Ansichten zu verbinden und dann das WHERE zu verwenden, um das Prädikat der resultierenden Menge einzuführen.

Es fühlt sich syntaktisch sauberer an.

Johnno Nolan
quelle
2

Ich sehe normalerweise Leistungssteigerungen beim Filtern nach dem Join. Insbesondere, wenn Sie indizierte Spalten für beide Tabellen verknüpfen können. Sie sollten in der Lage sein, logische Lesevorgänge bei den meisten Abfragen zu reduzieren, was in einer Umgebung mit hohem Volumen ein viel besserer Leistungsindikator als die Ausführungszeit ist.

Ich bin immer leicht amüsiert, wenn jemand sein SQL-Benchmarking zeigt und beide Versionen eines Sproc 50.000 Mal um Mitternacht auf dem Dev-Server ausgeführt und die Durchschnittszeiten verglichen hat.

marr75
quelle
0

Das Einfügen der Bedingung in den Join scheint mir "semantisch falsch" zu sein, da JOINs nicht "dafür" sind. Das ist aber sehr qualitativ.

Zusätzliches Problem: Wenn Sie sich entscheiden, von einem inneren Join zu einem richtigen Join zu wechseln, kann die Bedingung innerhalb des JOIN zu unerwarteten Ergebnissen führen.

Jacob B.
quelle
3
Manchmal sind diese Ergebnisse "erwartet" und manchmal sogar "beabsichtigt" (zum Beispiel bei äußeren Verknüpfungen, bei denen die WHERE-Bedingung eine andere Semantik als die JOIN-Bedingung hat).
Marcel Toth
0

Joins sind meiner Meinung nach schneller, wenn Sie einen größeren Tisch haben. Es ist wirklich kein so großer Unterschied, besonders wenn Sie es mit einem eher kleineren Tisch zu tun haben. Als ich zum ersten Mal von Joins erfuhr, wurde mir gesagt, dass Bedingungen in Joins genau wie Bedingungen für where-Klauseln sind und dass ich sie austauschbar verwenden könnte, wenn die where-Klausel spezifisch wäre, für welche Tabelle die Bedingung ausgeführt werden soll.

Eric
quelle
-4

Es ist besser, die Bedingung im Join hinzuzufügen. Leistung ist wichtiger als Lesbarkeit. Für große Datenmengen ist es wichtig.

Jeeno Shibu
quelle
1
Haben Sie einen Beweis dafür, wie sich die Platzierung der genannten Prädikate auf die Leistung auswirkt?
Zso