Frage

Ich bin zu wollen Zeilen in einer Tabelle auswählen, in dem der Primärschlüssel in einer anderen Tabelle ist. Ich bin mir nicht sicher, ob ich einen JOIN oder der IN-Operator in SQL Server verwenden sollte 2005. Gibt es einen signifikanten Performance-Unterschied zwischen diesen beide SQL-Abfragen mit einer großen Datenmenge (d Millionen von Zeilen)?

SELECT *
FROM a
WHERE a.c IN (SELECT d FROM b)

SELECT a.*
FROM a JOIN b ON a.c = b.d
War es hilfreich?

Lösung

Update:

In diesem Artikel in meinem Blog fasst sowohl meine Antwort und meine Kommentare zu anderen Antworten und zeigt die tatsächlichen Ausführungspläne:


SELECT  *
FROM    a
WHERE   a.c IN (SELECT d FROM b)

SELECT  a.*
FROM    a
JOIN    b
ON      a.c = b.d

Diese Abfragen sind nicht gleichwertig. Sie können unterschiedliche Ergebnisse liefern, wenn Ihre Tabelle b nicht beibehalten Schlüssel (i. E. Die Werte von b.d sind nicht eindeutig).

Das Äquivalent der ersten Abfrage ist die folgende:

SELECT  a.*
FROM    a
JOIN    (
        SELECT  DISTINCT d
        FROM    b
        ) bo
ON      a.c = bo.d

Wenn b.d UNIQUE und als solcher gekennzeichnet ist (mit einem UNIQUE INDEX oder UNIQUE CONSTRAINT), dann sind diese Abfragen identisch und die meisten werden wahrscheinlich identisch Pläne verwenden, da SQL Server intelligent genug, um dies zu berücksichtigen.

SQL Server kann eine der folgenden Methoden verwenden, um diese Abfrage auszuführen:

  • Wenn es ein Index auf a.c ist, d ist UNIQUE und b ist relativ klein im Vergleich zu a, dann wird der Zustand in die Unterabfrage propagiert wird und die Ebene INNER JOIN verwendet wird (mit b leading)

  • Wenn ein Index für b.d und d ist nicht UNIQUE, dann wird der Zustand auch vermehrt und LEFT SEMI JOIN verwendet wird. Es können sich auch für den Zustand verwendet werden.

  • Wenn es einen Index auf beiden b.d und a.c ist, und sie sind groß, dann MERGE SEMI JOIN verwendet wird

  • Wenn kein Index auf einer Tabelle ist, dann eine Hash-Tabelle auf b und HASH SEMI JOIN gebaut verwendet wird.

Weder diese Methoden reevaluates die ganze Unterabfrage jedes Mal.

Sehen Sie diesen Eintrag in meinem Blog für weitere Einzelheiten über, wie das funktioniert:

Es gibt Links für alle RDBMS die der großen vier.

Andere Tipps

Weder noch. Verwenden Sie ein ANSI-92 JOIN:

SELECT a.*
FROM a JOIN b a.c = b.d

Es ist jedoch am besten als ein EXISTS

SELECT a.*
FROM a
WHERE EXISTS (SELECT * FROM b WHERE a.c = b.d)

Das die Duplikate entfernen, die von der JOIN erzeugt werden könnten, läuft aber genauso schnell, wenn nicht schneller

Der IN ausgewertet (und die Auswahl aus b re-run) für jede Zeile in a, während die optimierte JOIN Indizes und anderen sauberen Paging Tricks zu verwenden ...

In den meisten Fällen jedoch würde der Optimierer wahrscheinlich in der Lage sein, um eine korrelierte Unterabfrage aus zu konstruieren JOIN und trotzdem mit dem gleichen Ausführungsplan enden.

Edit: Bitte die Kommentare lesen Sie unten für weitere ... Diskussion über die Gültigkeit dieser Antwort, und die eigentliche Antwort auf die Frage des OP. =)

aus Erfahrung auf einer Tabelle mit 49 Millionen Zeilen würde ich LEFT OUTER JOIN empfehlen. Unter Verwendung der in oder EXISTIERT dauerte 5 Minuten in Anspruch nehmen, wo die linke OUTER JOIN endet in 1 Sekunde.

SELECT a.*
FROM a LEFT OUTER JOIN b ON a.c = b.d
WHERE b.d is not null -- Given b.d is a primary Key with index

Eigentlich in meiner Anfrage Ich tue dies über 9 Tische.

Neben gehen und es tatsächlich zu testen für sich selbst auf einem großen Schwaden von Testdaten aus, würde ich sagen, die Verwendung beitritt. Ich hatte schon immer eine bessere Leistung sie in den meisten Fällen im Vergleich zu einer IN-Unterabfrage, und Sie haben so weit viel mehr Individualisierungsmöglichkeiten, wie man beitreten, was ausgewählt wird, was nicht ist, etc.

Sie sind verschiedene Abfragen mit unterschiedlichen Ergebnissen. Mit der IN-Abfrage werden Sie 1 Zeile aus der Tabelle erhalten ‚a‘, wenn das Prädikat übereinstimmt. Mit der INNER JOIN Abfrage werden Sie a * b Reihen erhalten, wenn die Bedingung Matches beitreten. So mit Werten in einem von {1,2,3} und b {1,2,2,3} werden Sie 1,2,2,3 vom JOIN und 1,2,3 aus dem IN erhalten.

EDIT - Ich glaube, Sie hier auf ein paar Antworten kommen können, die Ihnen eine falsche Vorstellung. Gehen Sie testen Sie es selbst und Sie werden sehen, diese sind alle in Ordnung Abfragepläne:

create table t1 (t1id int primary key clustered)
create table t2 (t2id int identity primary key clustered
    ,t1id int references t1(t1id)
)


insert t1 values (1)
insert t1 values (2)
insert t1 values (3)
insert t1 values (4)
insert t1 values (5)

insert t2 values (1)
insert t2 values (2)
insert t2 values (2)
insert t2 values (3)
insert t2 values (4)


select * from t1 where t1id in (select t1id from t2)
select * from t1 where exists (select 1 from t2 where t2.t1id = t1.t1id)
select t1.* from t1 join t2 on t1.t1id = t2.t1id

Die ersten beiden Pläne sind identisch. Der letzte Plan ist eine verschachtelte Schleife, diese Differenz, da erwartet wird, wie ich oben erwähnte der Join andere Semantik hat.

MSDN-Dokumentation auf Subquery Fundamentals :

  

Viele Transact-SQL-Anweisungen,   sind Unterabfragen können sein   so schließt sich alternativ formuliert.   Weitere Fragen können nur gestellt werden, mit   Unterabfragen. In Transact-SQL, gibt es   in der Regel keinen Unterschied in der Leistung   zwischen einer Aussage, die eine beinhaltet   Unterabfrage und eine semantisch äquivalente   Version, die nicht der Fall ist. Doch in   einige Fälle, wo Existenz muss sein   geprüft, verbinden sie eine Ausbeute besser   Performance. Andernfalls wird die verschachtelte   Abfrage muss für jeden verarbeitet werden   Ergebnis der äußeren Abfrage, um sicherzustellen,   Beseitigung von Duplikaten. In solch   Fällen würde eine Verknüpfung Ansatz ergeben   bessere Ergebnisse.

Im Beispiel Sie zur Verfügung gestellt haben, muss die verschachtelte Abfrage nur ein einziges Mal für jeden der äußeren Abfrageergebnisse verarbeitet werden, so sollte es kein Unterschied in der Leistung sein. Überprüfung der Ausführungspläne für beide Abfragen sollten dies bestätigen.

Hinweis: Obwohl sich die Frage nicht SQL Server 2005 angegeben haben, habe ich mit dieser Annahme beantwortet auf der Grundlage der Frage-Tags. Anderer Datenbank-Engines (auch verschiedene SQL Server-Versionen) kann nicht auf die gleiche Art und Weise optimieren.

Beachten Sie den Ausführungsplan für beide Typen und Ihre Schlüsse ziehen. Es sei denn, die Anzahl der Datensätze von der Unterabfrage in der „IN“ Anweisung zurück sehr klein ist, ist die IN-Variante an Sicherheit grenzender Wahrscheinlichkeit langsamer.

Ich würde verwenden eine Verknüpfung, wetten, dass es schneller ein verdammt viel sein werden als IN. Dies setzt voraus, dass es Primärschlüssel definiert ist, natürlich, damit Indexierungsgeschwindigkeit Dinge nachzulassen enorm.

Es wird allgemein angenommen, dass eine Verknüpfung wäre effizienter als die in Unterabfrage; aber die SQL * Server-Optimierer führen normalerweise zu keinem spürbaren Unterschied in der Leistung. Trotzdem ist es wahrscheinlich am besten, die Join-Bedingung codieren, indem Sie Ihre Standards konsistent zu halten. Auch wenn Ihre Daten und Code jemals in Zukunft migriert werden muss, kann nicht der Datenbank-Engine so nachsichtig sein (zum Beispiel unter Verwendung einer Verknüpfung anstelle einer IN subquery macht einen großen Unterschied in MySql).

Die Theorie wird nur erhalten Sie so weit auf Fragen wie diese. Am Ende des Tages, sollten Sie beiden Abfragen testen und sehen, welche tatsächlich schneller läuft. Ich habe Fälle gehabt, wo die JOIN-Version eine Minute übernahm und die IN-Version dauerte weniger als eine Sekunde. Ich habe auch Fälle, in denen schneller war eigentlich JOIN.

Persönlich neige ich mit der IN-Version zu starten, wenn ich weiß, ich werde keine Felder aus der Unterabfrage Tabelle benötigen. Wenn das langsam beginnt zu laufen, werde ich optimieren. Glücklicherweise für große Datensätze, die Abfrage Umschreiben macht solche einen spürbaren Unterschied, dass Sie es einfach aus Query Analyzer eine Zeit können und wissen, dass Sie Fortschritte machen.

Viel Glück!

Ive immer ein Anhänger der Methodik gewesen. Dieser Link enthält Details eines Tests in PostgresSQL durchgeführt. http://archives.postgresql.org/pgsql-performance/2005- 02 / msg00327.php

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top