Warum EXISTS anstatt IN?

PLSQL_SQL

SQL-Guru
Beiträge
176
Diese Frage ist anhand eines Beispiels am besten erklärt!

Example - IN:
Code:
select *
    from tabelle1 t1
    where t1.spalte1 IN ( select t2.spalte1 from tabelle2 t2 )

Diese liefert ALLE Datensätze von Tabelle1, wo die Spalte1 von Tabelle1 GLEICH der Spalte1 von Tabelle2 ist. (Tabelle1.Spalte1 = Tabelle2.Spalte1)

Jedoch wird für JEDEN Datensatz des äußeren Select-Stmt der Subselect in der where - Klause ausgeführt. Dies ist sehr performanceintensiv, vor allem, wenn Tabelle1 ODER Tabelle2 sehr viele Datensätze beinhaltet!!!

Example - EXISTS:
Code:
select *
    from tabelle1 t1
    where EXISTS ( select 'x' from tabelle2 t2 where t1.Spalte1 = t2.Spalte1 )

Diese liefert ALLE Datensätze von Tabelle1, wo die Spalte1 von Tabelle1 GLEICH der Spalte1 von Tabelle2 ist. (Tabelle1.Spalte1 = Tabelle2.Spalte1)
(wie bei "Example - IN")

Unterschied zu Example - IN:
Hier wird die äußere Select - Anweisung ausgeführt und das SQL-Resultset im Cache des DBMS gespeichert. Anschließend wird das Subselect ausgeführt und ebenfalls im Cache gespeichert.
Zuletzt werden beide SQL-Resultsets herangezogen und gejoined!!
Daher kommen wir wieder auf das gleiche Ergebnis ( Tabelle1.Spalte1 = Tabelle2.Spalte1 )
Somit ist die Performance deutlich besser als bei "IN"!!

Ich hoffe, ich habe mich verständlich ausgedrückt und es ist nachvollziehbar!

Lg
 
Werbung:
Kann es sein das es dort Unterschiede im DBMS gibt? Ich habe mit SQL 2008 R2 Express und einer Tabelle mit 2,1 Mio Datensätzen die sich selbst vergleicht ( Jede Abfrage dauert 17 Sekunden) und in Kombination mit einer Tabelle mit 4.806 Datensätzen (Dauer 1 Sekunde) keinen Unterschied provozieren können. In allen Fällen, ob EXISTS oder IN habe ich die gleiche Abfragedauer mehrfach reproduzieren können.

Entweder wird bei IN der Subselect genauso gecached wie bei EXISTS oder die 17 Sekunden sind eher netzwerkbedingt und die Unterscheide sind bei 2 Mio Datensätzen noch nicht messbar.
Code:
SELECT    *
FROM    z_unt_bez_fragmente -- 17 Sekunden, 2.104.674
SELECT    *
FROM    z_unt_bez_fragmente
WHERE    fk_untn IN (    SELECT    fk_untn
                        FROM    z_unt_bez_fragmente ) -- 17 Sekunden, 2.104.674
SELECT    *
FROM    z_unt_bez_fragmente t1
WHERE    EXISTS (    SELECT    1
                    FROM    z_unt_bez_fragmente t2
                    WHERE    t1.fk_untn = t2.fk_untm ) -- 17 Sekunden, 2.104.674
SELECT    *
FROM    z_unt_bez_fragmente t1
WHERE    EXISTS (    SELECT    1
                    FROM    ADRESSEN t2
                    WHERE    t2.SID_ADRESSEN = t1.fk_untm ) -- 17 Sekunden, 2.104.674
SELECT    *
FROM    z_unt_bez_fragmente
WHERE    fk_untn IN (    SELECT    SID_ADRESSEN
                        FROM    ADRESSEN ) -- 17 Sekunden, 2.104.674
SELECT    *
FROM    ADRESSEN
WHERE    SID_ADRESSEN IN (    SELECT    fk_untn
                            FROM    z_unt_bez_fragmente ) -- 1 Sekunde, 4.806
SELECT    *
FROM    ADRESSEN t1
WHERE    EXISTS (    SELECT    1
                    FROM    z_unt_bez_fragmente t2
                    WHERE    t1.SID_ADRESSEN = t2.fk_untm ) -- 1 Sekunde, 4.806
 
Das nenne ich echte Begeisterung!!!

Toll gemacht ukulele!!!!

Aber was ich noch nicht erwähnt habe, ist es doch so (bin mir gerade nicht ganz sicher), dass wenn im Subselect 2 Treffer zum äußeren Select gefunden werden, dass somit im äußeren Select 2 mal der gleiche Datensatz zurückgegeben wird. (1:n) Dies kann zwar mit DISTINCT verhindert werden, aber geht ziemlich sicher auf die Performance.

D.h. aus diesem Grund sollte doch auch EXISTS besser sein.

Keine Ahnung wie MSSQL 2008 R2 "IN" verarbeitet, vl. bilded dieser einen entsprechenden besseren Executionplan und behandelt das Subselect mit "IN" wie eine "EXISTS" !????

Auf Netzwerkprobleme würde ich hier auf keinen Fall tippen! 2 Mio Datensätze sind schon etwas, kommt jedoch auch auf die Leistungsstärke des Datenbankservers an, ab wann solche Dinge spürbar werden!

Lg
 
Ich habe bisher (auch in Fällen mit IN und DISTINCT) keine wirklichen Probleme gehabt, dennoch würde ich die EXISTS Lösung auch als eleganter ansehen. Bis vor geraumer Zeit wusste ich aber noch nichtmal, das ich im Subselect mit einem Alias auf Spalten aus dem Select gearbeitet werden kann :)

Beim Testserver handelt es sich übrigens um ein produktives Windows 2003 R2 auf VMware mit nur einem Core (SQL Express nutzt eh nur einen Kern) der sonst nicht sehr viel zu tun hat. Allerdings läuft unsere ganze produktive Umgebung auf nur 2 Hosts was die Abfragedauer aber nicht beeinflusst. Daher hatte ich überlegt das eventuell die Netzwerkanbindung des Clients (nur 100 MBit), der die SELECT Daten empfängt der begrenzende Faktor sein könnte.

PS: Die selbe Abfrage direkt auf dem Server dauert sogar 19 Sekunden. Ich denke mal ich will gar nicht wissen, warum^^
 
Werbung:
Cool!

Danke nochmals für dein Feedback!
Ich kann nur sagen, dass bei mir (Oracle 10g) immer ein deutlicher Unterschied zwischen "IN" und "EXISTS" besteht. Ich habe auch normale JOIN Abfragen mit EXISTS geteilt, um die JOINS somit in einem Stmt zu verringern und das Stmt zu beschleunigen. Dies ist jedoch nur möglich, wenn du in den letzteren Tabellen (welche du im EXISTS verwendest) KEINE Spalten (Attribute) zur Ausgabe benötigst!

Lg
 
Zurück
Oben