it-swarm.com.de

EXISTS vs JOIN und Verwendung der EXISTS-Klausel

Unten ist das Codebeispiel:

CREATE TABLE #titles(
    title_id       varchar(20),
    title          varchar(80)       NOT NULL,
    type           char(12)          NOT NULL,
    pub_id         char(4)               NULL,
    price          money                 NULL,
    advance        money                 NULL,
    royalty        int                   NULL,
    ytd_sales      int                   NULL,
    notes          varchar(200)          NULL,
    pubdate        datetime          NOT NULL
 )
 GO

 insert #titles values ('1', 'Secrets',   'popular_comp', '1389', $20.00, $8000.00, 10, 4095,'Note 1','06/12/94')
 insert #titles values ('2', 'The',       'business',     '1389', $19.99, $5000.00, 10, 4095,'Note 2','06/12/91')
 insert #titles values ('3', 'Emotional', 'psychology',   '0736', $7.99,  $4000.00, 10, 3336,'Note 3','06/12/91')
 insert #titles values ('4', 'Prolonged', 'psychology',   '0736', $19.99, $2000.00, 10, 4072,'Note 4','06/12/91')
 insert #titles values ('5', 'With',      'business',     '1389', $11.95, $5000.00, 10, 3876,'Note 5','06/09/91')
 insert #titles values ('6', 'Valley',    'mod_cook',     '0877', $19.99, $0.00,    12, 2032,'Note 6','06/09/91')
 insert #titles values ('7', 'Any?',      'trad_cook',    '0877', $14.99, $8000.00, 10, 4095,'Note 7','06/12/91')
 insert #titles values ('8', 'Fifty',     'trad_cook',    '0877', $11.95, $4000.00, 14, 1509,'Note 8','06/12/91')
 GO


CREATE TABLE #sales(
    stor_id        char(4)           NOT NULL,
    ord_num        varchar(20)       NOT NULL,
    ord_date       datetime          NOT NULL,
    qty            smallint          NOT NULL,
    payterms       varchar(12)       NOT NULL,
    title_id       varchar(80)
)
 GO
insert #sales values('1', 'QA7442.3', '09/13/94', 75, 'ON Billing','1')
insert #sales values('2', 'D4482',    '09/14/94', 10, 'Net 60',    '1')
insert #sales values('3', 'N914008',  '09/14/94', 20, 'Net 30',    '2')
insert #sales values('4', 'N914014',  '09/14/94', 25, 'Net 30',    '3')
insert #sales values('5', '423LL922', '09/14/94', 15, 'ON Billing','3')
insert #sales values('6', '423LL930', '09/14/94', 10, 'ON Billing','2')


SELECT    title, price
FROM      #titles
WHERE     EXISTS
(SELECT   *
FROM      #sales
WHERE     #sales.title_id = #titles.title_id
AND       qty >30)


    SELECT    t.title, t.price
    FROM     #titles t
    inner join #sales s on t.title_id = s.title_id
    where s.qty >30 

Ich möchte wissen, was der Unterschied zwischen den obigen 2 Abfragen ist, die das gleiche Ergebnis liefern. Möchten Sie auch den Zweck des EXISTS-Schlüsselworts kennen und wissen, wo genau es verwendet werden soll?

48
satyajit

EXISTS wird verwendet, um einen booleschen Wert zurückzugeben, JOIN gibt eine ganze andere Tabelle zurück

EXISTS wird nur verwendet, um zu testen, ob eine Unterabfrage Ergebnisse zurückgibt, und schließt diese kurz, sobald dies der Fall ist. JOIN wird verwendet, um eine Ergebnismenge zu erweitern, indem es mit zusätzlichen Feldern aus einer anderen Tabelle kombiniert wird, zu der eine Beziehung besteht.

In Ihrem Beispiel sind die Abfragen symmetrisch äquivalent.

Verwenden Sie im Allgemeinen EXISTS, wenn:

  • Sie müssen keine Daten aus der zugehörigen Tabelle zurückgeben
  • Sie haben Dupes in der zugehörigen Tabelle (JOIN kann bei wiederholten Werten zu doppelten Zeilen führen)
  • Sie möchten die Existenz überprüfen (verwenden Sie anstelle von LEFT OUTER JOIN...NULL Bedingung)

Wenn Sie über geeignete Indizes verfügen, verhält sich EXISTS die meiste Zeit genauso wie JOIN. Die Ausnahme bilden sehr komplizierte Unterabfragen, bei denen die Verwendung von EXISTS normalerweise schneller ist.

Wenn Ihr JOIN Schlüssel nicht indiziert ist, ist es möglicherweise schneller, EXISTS zu verwenden, aber Sie müssen auf Ihre spezifischen Umstände testen.

Die Syntax von JOIN ist normalerweise einfacher zu lesen und auch klarer.

99
JNK
  • EXISTS ist ein Semi-Join
  • JOIN ist ein Join

Also mit 3 Reihen und 5 Reihen passend

  • JOIN ergibt 15 Zeilen
  • EXISTS gibt 3 Zeilen

Das Ergebnis ist der von anderen erwähnte "Kurzschlusseffekt", und es ist nicht erforderlich, DISTINCT mit einem JOIN zu verwenden. EXISTS ist fast immer schneller, wenn Sie die Existenz von Zeilen auf der n-Seite einer 1: n-Beziehung suchen.

38
gbn

EXISTS wird hauptsächlich zur Verknüpfung verwendet. Im Wesentlichen wird der Optimierer aussteigen, sobald die Bedingung erfüllt ist, sodass möglicherweise nicht die gesamte Tabelle durchsucht werden muss (in modernen Versionen von SQL Server kann diese Optimierung auch für IN() erfolgen, dies war jedoch nicht der Fall immer wahr). Dieses Verhalten kann von Abfrage zu Abfrage variieren, und in einigen Fällen bietet der Join dem Optimierer möglicherweise mehr Gelegenheit, seine Arbeit zu erledigen. Ich denke, es ist schwer zu sagen, dass dies der Zeitpunkt ist, an dem Sie EXISTS verwenden sollten, und der Zeitpunkt, an dem Sie dies nicht tun sollten, weil es, wie bei vielen Dingen, davon abhängt.

In diesem Fall ist es jedoch unwahrscheinlich, dass Sie Leistungsunterschiede feststellen, da Sie im Wesentlichen eine 1: 1-Übereinstimmung zwischen den Tabellen haben, und der Optimierer wird wahrscheinlich einen ähnlichen oder sogar identischen Plan erstellen. Sie sehen möglicherweise etwas anderes, wenn Sie Join/Exists in der Verkaufstabelle vergleichen, wenn Sie 50.000 Zeilen für jeden Titel hinzufügen (egal, dass Sie Ihre Join-Abfrage ändern müssen, um Duplikate zu entfernen, aggregieren, was Sie haben).

10
Aaron Bertrand

Ich finde, dass Exists am nützlichsten sind, wenn ich Zeilen ausschließen möchte, basierend darauf, wie sie mit anderen Zeilen interagieren.

Beispielsweise,

SELECT * 
  FROM TABLE a
 WHERE a.val IN (1,2,3)
   AND NOT EXISTS(SELECT NULL
                    FROM TABLE b
                   WHERE b.id = a.id
                     AND b.val NOT IN (1, 2, 3))

In diesem Fall schließe ich eine Zeile in meiner a -Anfrage aus, die auf einem b -Datensatz mit derselben ID basiert, aber ungültig ist.

Dies kam tatsächlich von einem Produktionsproblem, das ich bei der Arbeit hatte . Durch die Abfrage wurde der größte Teil der Ausschlusslogik in der Abfrage anstelle der Anwendung verschoben. Die Ladezeit betrug mehr als 24 Sekunden und weniger als 2 Sekunden. :-)

3
corsiKa