2012-04-24 6 views
39
mit

Unter der Annahme, dass ich die folgenden T-SQL-Code haben:WHERE-Klausel vs ON, wenn JOIN

SELECT * FROM Foo f 
INNER JOIN Bar b ON b.BarId = f.BarId; 
WHERE b.IsApproved = 1; 

Die folgende man auch den gleichen Satz von Zeilen zurückgibt:

SELECT * FROM Foo f 
INNER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

Das ist nicht sein könnte das beste Beispiel hier, aber gibt es einen Leistungsunterschied zwischen diesen beiden?

+2

Hier ist eine ähnliche Frage: http://stackoverflow.com/questions/2509987/which-sql-query-is-faster-filter-on-join-criteria-or-where-klause –

+11

Die Maschine wird es herausfinden und optimieren Sie es richtig. Für die Menschen, die Debug-Modify-Unterstützung für Ihre Code-Jahre ab sofort benötigen, halten Sie die Filterbedingungen in der WHERE und verbinden Bedingungen in der ON. –

+0

@ KM. Ich weiß nicht immer, wie man den Unterschied zwischen einer Join-Bedingung und einem Filter erkennt. Zum Beispiel [in dieser Antwort] (http://stackoverflow.com/a/9303069/119477) denke ich, es ist besser in der Join so ist das eine "Join-Bedingung" dann? [Hier ist ein weiteres Beispiel] (http://Stackoverflow.com/a/6473403/119477), von dem ich nicht einmal weiß, wie ich die äquivalente Where-Klausel umschreiben soll. –

Antwort

28

Nein, der Abfrageoptimierer ist intelligent genug, um für beide Beispiele den gleichen Ausführungsplan auszuwählen.

Sie können den Ausführungsplan mit SHOWPLAN überprüfen.


Dennoch sollten Sie alle Verbindung auf der ON Join-Klausel setzen und alle Beschränkungen der WHERE Klausel.

+2

Beat mich dazu. Obwohl ich es bevorzugen würde, würde ich mit dem JOIN gehen, da es beschreibender ist. – Ste

+1

Danke! Stellen Sie sich eine Situation mit 7 oder 8 INNEREN VERBINDUNGEN vor. Ist Ihre Antwort auch auf diese Situationen anwendbar? – tugberk

+13

@Ste IMO, es ist tatsächlich verwirrender, alles in den 'JOIN' zu schreiben. Verwenden Sie 'JOIN', um sich auf Tabellen in einer Abfrage zu beziehen. Verwenden Sie 'WHERE', um Ergebnisse zu filtern. Wenn Sie die beiden mischen und ** nur ** verwenden, werden die Abfragen schwer lesbar. – Yuck

5
SELECT * FROM Foo f 
INNER JOIN Bar b ON b.BarId = f.BarId 
WHERE b.IsApproved = 1; 

Dies ist die bessere Form zu gehen. Es ist leicht zu lesen und zu modifizieren. In der Geschäftswelt ist das genau das, was Sie wollen. In Bezug auf die Leistung sind sie jedoch gleich.

+0

In meiner jetzigen Situation favorisiere ich die WHERE-Klausel, konnte aber nicht vermeiden, mich zu fragen, ob es ein perf diff gibt. Vielen Dank! – tugberk

42

Achten Sie nur auf den Unterschied mit den äußeren Verbindungen. Eine Abfrage, wo ein Filter von b.IsApproved (auf der rechten Tabelle, Bar) an den ON Zustand der JOIN hinzugefügt:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

Ist NICHT das gleiche wie die Filter in der WHERE Klausel Abdrucken:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) 
WHERE (b.IsApproved = 1); 

da für ‚nicht bestanden‘ Outer-Joins zu Bar (dh wo es keine b.BarId für eine f.BarId ist), diese b.IsApproved als NULL für alle diese fa verlassen Bei geblockten Join-Zeilen werden diese Zeilen herausgefiltert.

Ein anderer Weg, dies zu betrachten, ist, dass für die erste Abfrage, LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) wird die linken Tabellenzeilen immer wieder zurückkehren, da LEFT OUTER JOIN die linken Tabellenzeilen garantiert werden auch zurückgegeben werden, wenn die Verbindung fehlschlägt. Der Effekt des Hinzufügens von (b.IsApproved = 1) zu der Bedingung LEFT OUTER JOIN besteht jedoch darin, beliebige rechte Tabellenspalten zu NULLEN, wenn (b.IsApproved = 1) falsch ist, d. H. Nach den gleichen Regeln, die normalerweise auf eine LEFT JOIN Bedingung auf (b.BarId = f.BarId) angewendet werden.

aktualisieren: die Frage von Conrad, die äquivalente LOJ für einen optionalen Filter gefragt abzuschließen wäre:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) 
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1); 

dh die WHERE Klausel sowohl die Bedingung prüfen muss, ob die Verbindung fehlschlägt (NULL) und Der Filter wird ignoriert, und der Join ist erfolgreich und der Filter muss angewendet werden.(b.IsApproved oder b.BarId könnte für NULL getestet werden)

ich einen SqlFiddle together here gesetzt haben, die auf die JOIN die Unterschiede zwischen den verschiedenen Anordnungen des b.IsApproved Filters relativ zeigt.

+0

+1, guter Punkt! –

+0

Sehr guter Punkt. Wenn Sie Filterkriterien-Testdaten von einem äußeren Join in den äußeren Join selbst einfügen, erhalten Sie mehr Zeilen als erwartet, da alle Foos unabhängig vom Status oder der Existenz von Bar zurückgegeben werden. Wenn die Filterung getrennt vom Joining erfolgt, werden zuerst die Zeilen aus den beiden Tabellen verknüpft, und dann entfernt der Filter die gesamte Zeile aus der Tabelle, in der die Kriterien nicht erfüllt sind. – KeithS

+1

@nonnb Ok, aber wenn Sie die WHERE-Klausel in der 2. Frage zu 'WHERE b.IsApproved = 1 oder b.BarId ist Null, es ist dasselbe. Was machst du jetzt? um –

0

Ich habe einige Fälle, in denen der Optimierer nicht einmal in den letzten Versionen von MSSQL schlau genug war - und der Leistungsunterschied war Monster.

Aber dies ist eine Ausnahme, die meiste Zeit SQL Server Optimierer wird das Problem lösen und den richtigen Plan bekommen.

So halten Sie die Richtlinie der Filter auf WHERE-Klausel und optimieren Sie bei Bedarf.

0

Ich habe gerade einen Test einer Abfrage gegen vier Tabellen ausgeführt - eine Primärtabelle mit drei INNER JOINs und insgesamt vier Parameter und verglich die Ausführungspläne beider Ansätze (unter Verwendung der Filterkriterien im ON des JOIN, und dann auch in der WHERE-Klausel).

Die Ausführungspläne sind genau gleich. Ich habe dies auf SQL Server 2008 R2 ausgeführt.