Unterschied zwischen EXISTS und IN in SQL?

443

Was ist der Unterschied zwischen der EXISTSund IN-Klausel in SQL?

Wann sollten wir verwenden EXISTSund wann sollten wir verwenden IN?

Krantz
quelle

Antworten:

224

Das existsSchlüsselwort kann auf diese Weise verwendet werden, aber es ist wirklich dazu gedacht, das Zählen zu vermeiden:

--this statement needs to check the entire table
select count(*) from [table] where ...

--this statement is true as soon as one match is found
exists ( select * from [table] where ... )

Dies ist am nützlichsten, wenn Sie ifbedingte Anweisungen haben, da existsdies viel schneller sein kann als count.

Das inwird am besten verwendet, wenn Sie eine statische Liste übergeben müssen:

 select * from [table]
 where [field] in (1, 2, 3)

Wenn Sie eine Tabelle in einer inAnweisung haben, ist es sinnvoller, eine zu verwenden join, aber meistens sollte es keine Rolle spielen. Der Abfrageoptimierer sollte in beiden Fällen denselben Plan zurückgeben. In einigen Implementierungen (meistens älter, wie z. B. Microsoft SQL Server 2000) erhalten inAbfragen immer einen verschachtelten Join- Plan, während joinAbfragen je nach Bedarf verschachtelt, zusammengeführt oder hashen . Modernere Implementierungen sind intelligenter und können den Plan auch bei inVerwendung anpassen .

Keith
quelle
2
Könnten Sie näher auf "Wenn Sie eine Tabelle in einer in-Anweisung haben, ist es sinnvoller, einen Join zu verwenden, aber das spielt keine Rolle. Der Abfrageoptimierer gibt in beiden Fällen denselben Plan zurück." Nicht der Teil des Abfrageoptimierers, der Teil, für den Sie einen JOINals Ersatz verwenden können IN.
FarthVader
select * from [table] where [field] in (select [field] from [table2])Gibt die gleichen Ergebnisse (und Abfragepläne) wie zurück select * from [table] join [table2] on [table2].[field] = [table].[field].
@Sander ist es nicht: Die erste Abfrage gibt alle Spalten von zurück table, während die zweite alles von tableund zurückgibt table2. In einigen (meist älteren) SQL-Datenbanken wird die inAbfrage als verschachtelter Join implementiert, während die joinAbfrage verschachtelt, zusammengeführt, gehasht usw. werden kann - was auch immer am schnellsten ist.
Keith
2
Okay, ich hätte Spalten in der select-Klausel angeben sollen, aber Sie sollten Ihre Antwort aktualisieren, da darin eindeutig angegeben ist, dass die Abfragen "in beiden Fällen denselben Plan zurückgeben".
existskann innerhalb einer case-Anweisung verwendet werden, so dass sie auch auf diese Weise nützlich sein können, dhselect case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
glatt_smoothie
125

EXISTSHier erfahren Sie, ob eine Abfrage Ergebnisse zurückgegeben hat. z.B:

SELECT * 
FROM Orders o 
WHERE EXISTS (
    SELECT * 
    FROM Products p 
    WHERE p.ProductNumber = o.ProductNumber)

IN wird verwendet, um einen Wert mit mehreren zu vergleichen, und kann Literalwerte wie diesen verwenden:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (1, 10, 100)

Sie können Abfrageergebnisse auch mit der folgenden INKlausel verwenden:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)
Matt Hamilton
quelle
3
Die letzte Abfrage ist gefährlich, da sie möglicherweise fehlschlägt, wenn die Unterabfrage keine Ergebnisse zurückgibt. 'in' Klausel erfordert mindestens 1 Argument ...
user2054927
40
@ user2054927 Die letzte Abfrage gibt keine Zeilen korrekt zurück, wenn die Unterabfrage keine Zeilen zurückgibt - nichts Gefährliches daran!
Tony Andrews
Die beste Antwort.
Aminadav Glickshtein
81

Basierend auf dem Regeloptimierer :

  • EXISTSist viel schneller als INwenn die Ergebnisse der Unterabfrage sehr groß sind.
  • INist schneller als EXISTS, wenn die Ergebnisse der Unterabfrage sehr klein sind.

Basierend auf dem Kostenoptimierer :

  • Es gibt keinen Unterschied.
Jackson
quelle
21
Beweis Ihrer Argumentation? Ich denke nicht, dass IN schneller sein würde als EXISTS jemals!
Nawaz
22
@Nawaz Wie wäre es mit dem Beweis, warum IN immer langsamer ist als EXISTS?
10.
2
Schlecht implementierter Abfrageoptimierer? Ich habe den Eindruck, dass so etwas (wenn auch nicht genau diese Situation) in bestimmten RDBMs passiert ...
Haroldo_OK
1
EXISTS gibt rein boolesche Werte zurück, was immer schneller ist, als Zeichenfolgen oder Werte zu vergleichen, die größer als ein BIT / Boolescher Typ sind. IN kann ein boolescher Vergleich sein oder nicht. Da die Programmierung die Verwendung von EXPLICIT aus Stabilitätsgründen bevorzugt (Teil von ACID), wird EXISTS im Allgemeinen bevorzugt.
Clifton_h
2
Warum wurde das so oft positiv bewertet? Es gibt absolut keinen Grund, warum diese auf Annahmen basierende Aussage im Allgemeinen wahr sein sollte.
Lukas Eder
40

Ich gehe davon aus, dass Sie wissen, was sie tun, und daher anders verwendet werden. Daher verstehe ich Ihre Frage wie folgt: Wann wäre es eine gute Idee, das SQL neu zu schreiben, um IN anstelle von EXISTS zu verwenden, oder umgekehrt.

Ist das eine faire Annahme?


Bearbeiten : Der Grund, den ich frage, ist, dass Sie in vielen Fällen eine auf IN basierende SQL neu schreiben können, um stattdessen EXISTS zu verwenden, und umgekehrt. Bei einigen Datenbank-Engines behandelt das Abfrageoptimierungsprogramm die beiden unterschiedlich.

Zum Beispiel:

SELECT *
FROM Customers
WHERE EXISTS (
    SELECT *
    FROM Orders
    WHERE Orders.CustomerID = Customers.ID
)

kann umgeschrieben werden in:

SELECT *
FROM Customers
WHERE ID IN (
    SELECT CustomerID
    FROM Orders
)

oder mit einem Join:

SELECT Customers.*
FROM Customers
    INNER JOIN Orders ON Customers.ID = Orders.CustomerID

Meine Frage bleibt also weiterhin: Ist das Originalplakat eine Frage, was IN und EXISTS tun und wie man es verwendet, oder ob er eine SQL mit IN neu schreibt, um stattdessen EXISTS zu verwenden, oder umgekehrt, eine gute Idee ist?

Lasse V. Karlsen
quelle
12
Ich weiß nichts über das OP, aber ich möchte die Antwort auf diese Frage! Wann sollte ich EXISTS anstelle von IN mit einer Unterabfrage verwenden, die IDs zurückgibt?
Roy Tinker
8
in der JOINbenötigen Sie eineDISTINCT
Jaider
4
tolle Demonstration, aber so ziemlich die Frage unbeantwortet lassen
Junchen Liu
28
  1. EXISTSist viel schneller als INwenn die Ergebnisse der Unterabfrage sehr groß sind.
    INist schneller als EXISTSwenn die Ergebnisse der Unterabfrage sehr klein sind.

    CREATE TABLE t1 (id INT, title VARCHAR(20), someIntCol INT)
    GO
    CREATE TABLE t2 (id INT, t1Id INT, someData VARCHAR(20))
    GO
    
    INSERT INTO t1
    SELECT 1, 'title 1', 5 UNION ALL
    SELECT 2, 'title 2', 5 UNION ALL
    SELECT 3, 'title 3', 5 UNION ALL
    SELECT 4, 'title 4', 5 UNION ALL
    SELECT null, 'title 5', 5 UNION ALL
    SELECT null, 'title 6', 5
    
    INSERT INTO t2
    SELECT 1, 1, 'data 1' UNION ALL
    SELECT 2, 1, 'data 2' UNION ALL
    SELECT 3, 2, 'data 3' UNION ALL
    SELECT 4, 3, 'data 4' UNION ALL
    SELECT 5, 3, 'data 5' UNION ALL
    SELECT 6, 3, 'data 6' UNION ALL
    SELECT 7, 4, 'data 7' UNION ALL
    SELECT 8, null, 'data 8' UNION ALL
    SELECT 9, 6, 'data 9' UNION ALL
    SELECT 10, 6, 'data 10' UNION ALL
    SELECT 11, 8, 'data 11'
  2. Abfrage 1

    SELECT
    FROM    t1 
    WHERE   not  EXISTS (SELECT * FROM t2 WHERE t1.id = t2.t1id)

    Abfrage 2

    SELECT t1.* 
    FROM   t1 
    WHERE  t1.id not in (SELECT  t2.t1id FROM t2 )

    Wenn t1Ihre ID den Wert Null hat, werden sie von Abfrage 1 gefunden, aber Abfrage 2 kann keine Nullparameter finden.

    Ich meine, ich INkann nichts mit null vergleichen, also hat es kein Ergebnis für null, aber ich kann alles mit null EXISTSvergleichen.

Alireza Masali
quelle
Diese Antwort ist eine vernünftige Zusammenfassung von Tom Kites Gefühl ( asktom.oracle.com/pls/asktom/… )
Jeromy French
Ich denke, diese Antwort basiert auf Intuition, was fair genug ist. Aber es kann nicht allgemein wahr sein. Zum Beispiel trifft dies mit ziemlicher Sicherheit nicht auf Ingres zu , bei dem beide äquivalenten SQL-Abfragen als dieselbe QUEL-Abfrage analysiert werden, bei der es an SQLs - ähm - "Reichtum" mangelt, wenn es darum geht, dasselbe auf mehrere Arten zu schreiben.
Tag, wenn
Diese beiden Abfragen sind genau dann logisch äquivalent, wenn t2.id als "NOT NULL" definiert ist. Um die Äquivalenz ohne Abhängigkeit in der Tabellendefinition zu gewährleisten, sollte die zweite Abfrage "SELECT t1. * FROM t1 WHERE t1.id not in (SELECT t2.id FROM t2, wobei t2.id nicht null ist )" sein
David דודו Markovitz
16

Wenn Sie den INOperator verwenden, scannt die SQL-Engine alle Datensätze, die aus der inneren Abfrage abgerufen wurden. Wenn wir dagegen verwenden EXISTS, stoppt die SQL-Engine den Scanvorgang, sobald eine Übereinstimmung gefunden wurde.

Wenn Sie den IN-Operat verwenden
quelle
10

IN unterstützt nur Gleichheitsrelationen (oder Ungleichheit, wenn NICHT vorangestellt ist ).
Es ist ein Synonym für = any / = some , z

select    * 
from      t1 
where     x in (select x from t2)
;

EXISTS unterstützt verschiedene Arten von Beziehungen, die nicht mit IN ausgedrückt werden können , z.

select    * 
from      t1 
where     exists (select    null 
                  from      t2 
                  where     t2.x=t1.x 
                        and t2.y>t1.y 
                        and t2.z like '℅' || t1.z || '℅'
                  )
;

Und in einem anderen Sinne -

Die angeblichen Leistungs- und technischen Unterschiede zwischen EXISTS und IN können auf Implementierungen / Einschränkungen / Fehler bestimmter Anbieter zurückzuführen sein. Oft handelt es sich jedoch nur um Mythen, die aufgrund mangelnden Verständnisses der internen Datenbanken entstanden sind.

Die Definition der Tabellen, die Genauigkeit der Statistiken, die Datenbankkonfiguration und die Version des Optimierers wirken sich alle auf den Ausführungsplan und damit auf die Leistungsmetriken aus.

David דודו Markovitz
quelle
Upvote für Ihren Kommentar zur Leistung: Ohne sich auf ein bestimmtes DBMS zu konzentrieren, sollten wir davon ausgehen, dass es Sache des Optimierers ist, herauszufinden, was am besten funktioniert.
Manngo
9

Das ExistsSchlüsselwort wertet wahr oder falsch aus, aber das INSchlüsselwort vergleicht alle Werte in der entsprechenden Unterabfragespalte. Ein anderer Select 1kann mit ExistsBefehl verwendet werden. Beispiel:

SELECT * FROM Temp1 where exists(select 1 from Temp2 where conditions...)

Ist INaber weniger effizient so Existsschneller.

Arulraj.M
quelle
5

Ich glaube,

  • EXISTSIn diesem Fall müssen Sie die Ergebnisse der Abfrage mit einer anderen Unterabfrage abgleichen. Die Ergebnisse der Abfrage Nr. 1 müssen abgerufen werden, wenn die SubQuery-Ergebnisse übereinstimmen. Art eines Joins. Wählen Sie beispielsweise die Kundentabelle Nr. 1 aus, die auch die Bestelltabelle Nr. 2 aufgegeben hat

  • IN soll abrufen, ob der Wert einer bestimmten Spalte in INeiner Liste liegt (1,2,3,4,5). ZB Kunden auswählen, die in den folgenden Postleitzahlen liegen, dh Postleitzahlwerte liegen in der Liste (....).

Wann man es übereinander verwendet ... wenn man das Gefühl hat, dass es angemessen liest (kommuniziert Absicht besser).

Gishu
quelle
4

Der Unterschied liegt hier:

select * 
from abcTable
where exists (select null)

Die obige Abfrage gibt alle Datensätze zurück, während die untere Abfrage leer zurückgibt.

select *
from abcTable
where abcTable_ID in (select null)

Probieren Sie es aus und beobachten Sie die Ausgabe.

Schurkenjunge
quelle
1
Hmmm ... Fehler: [SQL0104] Token) war ungültig. In beiden Fällen. Nehmen Sie ein bestimmtes RDBMS an?
Jmarkmurphy
3

Nach meinem Wissen NULLwird die gesamte Anweisung, wenn eine Unterabfrage einen Wert zurückgibt NULL. In diesen Fällen verwenden wir das EXITSSchlüsselwort. Wenn wir bestimmte Werte in Unterabfragen vergleichen möchten, verwenden wir das INSchlüsselwort.

RAM
quelle
3

Welche schneller ist, hängt von der Anzahl der von der inneren Abfrage abgerufenen Abfragen ab:

  • Wenn Ihre innere Abfrage Tausende von Zeilen abruft, ist EXIST die bessere Wahl
  • Wenn Ihre innere Abfrage nur wenige Zeilen abruft, ist IN schneller

EXIST bewertet auf wahr oder falsch, aber IN vergleicht mehrere Werte. Wenn Sie nicht wissen, dass der Datensatz vorhanden ist oder nicht, sollten Sie EXIST wählen

Sumair Hussain Rajput
quelle
3

Der Grund dafür ist, dass der EXISTS-Operator nach dem Prinzip „zumindest gefunden“ arbeitet. Es gibt true zurück und stoppt das Scannen der Tabelle, sobald mindestens eine übereinstimmende Zeile gefunden wurde.

Wenn andererseits der IN-Operator mit einer Unterabfrage kombiniert wird, muss MySQL zuerst die Unterabfrage verarbeiten und dann das Ergebnis der Unterabfrage verwenden, um die gesamte Abfrage zu verarbeiten.

Als Faustregel gilt, dass der EXISTS-Operator eine bessere Leistung bietet, wenn die Unterabfrage ein großes Datenvolumen enthält.

Die Abfrage, die den IN-Operator verwendet, wird jedoch schneller ausgeführt, wenn die von der Unterabfrage zurückgegebene Ergebnismenge sehr klein ist.

Vipin Jain
quelle
1

Meines Wissens nach sollten beide gleich sein, solange es sich nicht um NULL-Werte handelt.

Der gleiche Grund, warum die Abfrage den Wert für = NULL vs nicht zurückgibt, ist NULL. http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

Was das Argument Boolean vs Comparator betrifft, müssen zum Generieren eines Boolean beide Werte verglichen werden, und so funktioniert jede Bedingung, wenn sie funktioniert. Daher verstehe ich nicht, wie sich IN und EXISTS unterschiedlich verhalten.

Ranjeeth
quelle
0

Wenn eine Unterabfrage mehr als einen Wert zurückgibt, müssen Sie möglicherweise die äußere Abfrage ausführen, wenn die Werte in der in der Bedingung angegebenen Spalte mit einem Wert in der Ergebnismenge der Unterabfrage übereinstimmen. Um diese Aufgabe auszuführen, müssen Sie das inSchlüsselwort verwenden.

Sie können eine Unterabfrage verwenden, um zu überprüfen, ob eine Reihe von Datensätzen vorhanden ist. Dazu müssen Sie die existsKlausel mit einer Unterabfrage verwenden. Das existsSchlüsselwort gibt immer den Wert true oder false zurück.

Djohn
quelle
0

Ich glaube, das hat eine einfache Antwort. Warum überprüfen Sie es nicht von den Leuten, die diese Funktion in ihren Systemen entwickelt haben?

Wenn Sie ein MS SQL-Entwickler sind, finden Sie hier die Antwort direkt von Microsoft.

IN::

Legt fest, ob ein angegebener Wert mit einem Wert in einer Unterabfrage oder einer Liste übereinstimmt.

EXISTS::

Gibt eine Unterabfrage an, die auf das Vorhandensein von Zeilen getestet werden soll.

Fataler Fehler
quelle
0

Ich habe festgestellt, dass die Verwendung des EXISTS-Schlüsselworts oft sehr langsam ist (das ist in Microsoft Access sehr richtig). Ich verwende stattdessen den Join-Operator auf folgende Weise: Sollte-ich-das-Schlüsselwort-verwenden-existiert-in-SQL

Axel Der
quelle
-1

EXISTS ist schneller in der Leistung als IN. Wenn sich die meisten Filterkriterien in einer Unterabfrage befinden, ist es besser, IN zu verwenden. Wenn sich die meisten Filterkriterien in der Hauptabfrage befinden, ist es besser, EXISTS zu verwenden.

Deva
quelle
Diese Behauptung wird wirklich nicht durch irgendwelche Beweise gestützt, oder?
Lukas Eder
-2

Wenn Sie den IN-Operator verwenden, scannt die SQL-Engine alle Datensätze, die aus der inneren Abfrage abgerufen wurden. Wenn wir dagegen EXISTS verwenden, stoppt die SQL-Engine den Scanvorgang, sobald eine Übereinstimmung gefunden wurde.

Gagandeep Singh
quelle
@ziggy erklären? Dies ist so ziemlich das, was die akzeptierte Antwort auch sagt. Bei MUSS jeder einzelne Datensatz überprüft werden, kann vorhanden sein, sobald nur ein Datensatz gefunden wird.
Ben Thurley
Nein, nicht richtig. INund EXISTSkann äquivalent und ineinander transformiert sein.
Lukas Eder