Frage

Welche dieser Fragen ist die schneller?

NICHT VORHANDEN:

SELECT ProductID, ProductName 
FROM Northwind..Products p
WHERE NOT EXISTS (
    SELECT 1 
    FROM Northwind..[Order Details] od 
    WHERE p.ProductId = od.ProductId)

oder nicht:

SELECT ProductID, ProductName 
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
    SELECT ProductID 
    FROM Northwind..[Order Details])

Der Abfrage-Ausführungsplan sagt, dass sie beide das gleiche tun. Wenn das der Fall ist, die die empfohlene Form ist?

Dies basiert auf der Datenbank Northwind.

[Bearbeiten]

gefunden einfach diesen hilfreichen Artikel: http://weblogs.sqlteam.com/mladenp/archive/2007 /05/18/60210.aspx

Ich glaube, ich bleibe mit NICHT VORHANDEN.

War es hilfreich?

Lösung

ich immer standardmäßig NOT EXISTS.

Die Ausführungspläne können gleich im Moment, aber wenn entweder Spalte wird in Zukunft geändert NULLs die NOT IN Version mehr Arbeit tun müssen, damit (auch wenn keine NULLs in den Daten tatsächlich vorhanden sind) und die Semantik NOT IN wenn NULLs sind vorhanden sind unwahrscheinlich, die, die Sie auf jeden Fall wollen.

Wenn weder Products.ProductID oder [Order Details].ProductID erlaubt NULLs die NOT IN identisch mit der folgenden Abfrage behandelt werden.

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId) 

Der genaue Plan kann variieren, aber für mein Beispiel Daten erhalte ich die folgende.

Weder NULL

Ein recht verbreiteter Irrtum, scheint zu sein, dass korrelierte Unterabfragen sind immer „schlecht“ im Vergleich zu beitritt. Sie können sicher sein, wenn sie einen verschachtelten Schleife Plan (Unterabfrage ausgewertet Zeile für Zeile) zwingen, aber dieser Plan enthält ein Anti halb logischen Operator verbinden. Anti Semi-Joins ist nicht auf verschachtelte Schleifen beschränkt, sondern kann Hash verwenden oder fusionieren (wie in diesem Beispiel) schließt sich auch.

/*Not valid syntax but better reflects the plan*/ 
SELECT p.ProductID,
       p.ProductName
FROM   Products p
       LEFT ANTI SEMI JOIN [Order Details] od
         ON p.ProductId = od.ProductId 

Wenn [Order Details].ProductID ist NULL-able die Abfrage wird dann

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL) 

Der Grund dafür ist, dass die richtige Semantik, wenn [Order Details] keine NULL ProductIds enthält, ist keine Ergebnisse zurück. Siehe die zusätzlichen anti halb verbinden und Zeilenanzahl Spule dies zu überprüfen, ob der Plan hinzugefügt wird.

Ein NULL

Wenn Products.ProductID ist auch die Abfrage zu werden NULL-Lage verändert, dann wird

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL)
       AND NOT EXISTS (SELECT *
                       FROM   (SELECT TOP 1 *
                               FROM   [Order Details]) S
                       WHERE  p.ProductID IS NULL) 

Der Grund für dieses ist, weil ein NULL Products.ProductId nicht in den Ergebnissen außer , wenn die NOT IN Sub-Abfrage überhaupt keine Ergebnisse zurück waren (das heißt die [Order Details] Tabelle leer ist) zurückgegeben werden soll. In diesem Fall sollte. Im Plan für mein Beispieldaten wird dies durch das Hinzufügen eines weiteren anti halb wie unten kommen implementiert.

Both NULL

Die Wirkung dieser wird in mit ungeeigneten verschachtelten Schleifen verursachen wiederholte Ausführung einer teueren Unterstruktur beispielsweise .

Dies ist nicht der einzig mögliche Ausführungsplan für eine NOT IN auf eine NULL-able Spalte jedoch. Dieser Artikel zeigt ein anderes für eine Abfrage für die AdventureWorks2008 Datenbank.

Für die NOT IN auf einer NOT NULL Säule oder der NOT EXISTS gegen entweder eine nullable oder nicht NULL festlegbare Spalte den folgenden Plan gibt.

Nicht vorhanden

Wenn die Spalte Änderungen an NULL-Lage der NOT IN Plan sieht nun wie

Not In - Null

Es fügt eine zusätzliche innere Operator dem Plan beizutreten. Dieses Gerät ist hier erklärt. Es ist alles da die vorherige Single zu konvertierenkorrelierter Index auf Sales.SalesOrderDetail.ProductID = <correlated_product_id> zwei suchen sucht pro äußeren Reihe. Die zusätzliche ist auf WHERE Sales.SalesOrderDetail.ProductID IS NULL.

Da dies unter einem anti halb beitreten, wenn, dass man keine Zeilen zurückgibt die zweite Such wird nicht auftreten. Allerdings, wenn Sales.SalesOrderDetail enthält keine NULL ProductIDs es wird die Anzahl der Suchvorgänge verdoppelt erforderlich.

Andere Tipps

Beachten Sie auch, dass NICHT IN nicht gleichwertig ist, nicht vorhanden ist, wenn es auf null geht.

Dieser Beitrag erklärt es sehr gut

http://sqlinthewild.co.za/ index.php / 2010/02/18 / nicht-vorhanden-vs-nicht-in /

  

Wenn die Unterabfrage gibt sogar eine Null, wird nicht nicht überein   Zeilen.

     

Der Grund hierfür kann durch einen Blick auf die Details, was die gefunden werden   Nicht in Betrieb eigentlich bedeutet.

     

Lassen Sie uns sagen, zur Veranschaulichung, dass es 4 Reihen in der   Tabelle namens t, gibt es eine Spalte mit dem Namen ID mit Werten 1..4

WHERE SomeValue NOT IN (SELECT AVal FROM t)
     

entspricht

WHERE SomeValue != (SELECT AVal FROM t WHERE ID=1)
AND SomeValue != (SELECT AVal FROM t WHERE ID=2)
AND SomeValue != (SELECT AVal FROM t WHERE ID=3)
AND SomeValue != (SELECT AVal FROM t WHERE ID=4)
     

Lassen Sie uns weiter sagen, dass Aval NULL ist, wo ID = 4. Daher das! =   Vergleich liefert UNKNOWN. Die logische Wahrheitstabelle für AND Staaten   dass UNKNOWN und TRUE ist unbekannt, unbekannt und FALSCH FALSCH. Es gibt   kein Wert, der mit UNKNOWN werden verknüpft, kann das Ergebnis TRUE

zu erzeugen,      

Wenn also jede Zeile dieser Unterabfrage gibt NULL zurück, die gesamte NICHT IN   werden von einem Operator entweder FALSE oder NULL auszuwerten und keine Datensätze werden   zurück

Wenn die Ausführungsplaner sagt sie gleich sind, sind sie gleich. Verwenden Sie je nachdem, welche Ihre Absicht noch deutlicher machen -. In diesem Fall der zweite

Tatsächlich, ich glaube, dass dies der schnellste sein würde:

SELECT ProductID, ProductName 
    FROM Northwind..Products p  
          outer join Northwind..[Order Details] od on p.ProductId = od.ProductId)
WHERE od.ProductId is null

Ich habe eine Tabelle, die etwa 120.000 Datensätze hat und nur diejenigen auswählen muß, die nicht (mit einer Varchar-Spalte angepasst) existieren in vier anderen Tabellen mit Anzahl der Zeilen ca. 1500, 4000, 40000, 200. All beteiligten Tabellen haben eindeutigen Index für die betreffende Varchar Spalte.

NOT IN etwa 10 Minuten dauerte, nahm NOT EXISTS 4 Sekunden.

Ich habe eine rekursive Abfrage, die einige nicht abgestimmte Abschnitt könnte hatte, die an die 10 Minuten beigetragen haben könnte, aber die andere Option unter 4 Sekunden erklärt, mir atleast dass NOT EXISTS weit besser ist, oder zumindest, dass IN und EXISTS nicht genau die gleiche und immer eine Überprüfung wert, bevor mit dem Code ging voran.

In Ihrem speziellen Beispiel sind sie gleich, da der Optimierer herausgefunden hat, was Sie versuchen, das gleiche in beiden Beispielen zu tun ist. Aber es ist möglich, dass in nicht-triviale Beispiele der Optimierer dies nicht tun kann, und in diesem Fall gibt es Gründe, die man für andere gelegentlich bevorzugen.

NOT IN sollte bevorzugt sein, wenn Sie mehrere Zeilen in Ihrer äußeren Auswahl testen. Die Unterabfrage in der NOT IN Anweisung kann zu Beginn der Ausführung bewertet werden, und die temporäre Tabelle kann in der äußeren Auswahl gegen jeden Wert überprüft werden, anstatt wieder laufen die subselect jedes Mal, als würde mit der NOT EXISTS Anweisung erforderlich.

Wenn die Unterabfrage muss mit der Außen wählen korreliert werden, dann kann NOT EXISTS vorzuziehen sein, da der Optimierer eine Vereinfachung entdecken kann, die die Erstellung einer temporären Tabellen verhindert, dass die gleiche Funktion auszuführen.

Ich war mit

SELECT * from TABLE1 WHERE Col1 NOT IN (SELECT Col1 FROM TABLE2)

und stellte fest, dass es zu falschen Ergebnissen gab (von falsch meine ich keine Ergebnisse). Da war in TABLE2.Col1 ein NULL.

Während die Änderung der Abfrage

SELECT * from TABLE1 T1 WHERE NOT EXISTS (SELECT Col1 FROM TABLE2 T2 WHERE T1.Col1 = T2.Col2)

gab mir die richtigen Ergebnisse.

Seitdem habe ich begonnen VORHANDEN mit nicht jedem wo.

Sie sind sehr ähnlich, aber nicht wirklich das gleiche.

Im Hinblick auf die Effizienz, habe ich die gefunden LEFT JOIN ist null Erklärung effizienter (wenn eine Fülle von Zeilen ausgewählt werden, das ist)

Wenn der Optimierer sagt sie gleich sind dann den menschlichen Faktor in Betracht ziehen. Ich ziehe es sehen NICHT VORHANDEN:)

Es hängt ..

SELECT x.col
FROM big_table x
WHERE x.key IN( SELECT key FROM really_big_table );

wäre nicht verhältnismäßig langsam die nicht viel Größe zu beschränken, was die Abfrage überprüfen, ob sie Schlüssel in ist. VORHANDEN in diesem Fall vorzuziehen wäre.

Aber auf dem Optimierer DBMS abhängig, könnte dies nicht anders sein.

Als ein Beispiel, wenn EXISTS ist besser

SELECT x.col
FROM big_table x
WHERE EXISTS( SELECT key FROM really_big_table WHERE key = x.key);
  AND id = very_limiting_criteria
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top