SQL'de EXISTS ve IN arasındaki fark nedir?


443

SQL'de EXISTSve INdeyimi arasındaki fark nedir ?

Ne zaman EXISTSve ne zaman kullanmalıyız IN?

Yanıtlar:


224

existsAnahtar kelime bu şekilde kullanılabilir, ancak gerçekten önlemek sayma için bir yol olarak niyetiyle:

--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 ... )

Bu, ifkoşullu ifadeleriniz olduğunda en kullanışlıdır , çünkü existsdaha hızlı olabilircount .

En iniyi, iletilecek statik bir listeniz olduğunda kullanılır:

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

Bir inifadede bir tablonuz olduğunda, a'yı kullanmak daha mantıklıdır join, ancak çoğunlukla önemli olmamalıdır. Sorgu iyileştirici aynı planı her iki şekilde de döndürmelidir. Bazı uygulamalarda (çoğunlukla Microsoft SQL Server 2000 gibi daha eski) insorgular her zaman iç içe bir birleştirme planı alırken, joinsorgular iç içe, birleştirme veya karmayı uygun şekilde kullanır. Daha modern uygulamalar daha akıllıdır ve inkullanıldığında bile planı ayarlayabilir .


2
"İn deyiminde bir tablonuz olduğunda bir birleştirmeyi kullanmak daha mantıklı, ama gerçekten önemli değil. Sorgu eniyileştirici aynı planı her iki şekilde de döndürecektir." Sorgu eniyileyici bölümü değil, JOINyerine a olarak kullanabileceğiniz bölüm IN.
farthVader

select * from [table] where [field] in (select [field] from [table2])ile aynı sonuçları (ve sorgu planını) döndürür select * from [table] join [table2] on [table2].[field] = [table].[field].

Öyle değil @Sander: İlk sorgu döndürür tüm sütunlar arasından table, ikinci döner her şeyi yaparken tableve table2. Bazı (çoğunlukla eski) SQL veritabanlarında insorgu iç içe birleştirme olarak uygulanırken, joinsorgu iç içe geçmiş, birleştirilebilir, karma, vb.
Keith

2
Tamam, select yan tümcesinde sütunları belirtmeliydim, ancak sorgunun "aynı planı her iki şekilde de döndüreceğini" açıkça belirttiğinden cevabınızı güncellemelisiniz.

existsbir vaka ifadesi içinde kullanılabilir, bu yüzden de bu şekilde kullanışlı olabilir yaniselect case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie

125

EXISTSbir sorgunun sonuç döndürüp döndürmediğini size bildirir. Örneğin:

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

IN , bir değeri birkaç ile karşılaştırmak için kullanılır ve aşağıdaki gibi değişmez değerleri kullanabilir:

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

Ayrıca, INyan tümce ile sorgu sonuçlarını aşağıdaki gibi kullanabilirsiniz:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)

3
Son sorgu tehlikelidir, çünkü alt sorgunun herhangi bir sonuç döndürmemesi durumunda başarısız olabilir. 'in' yantümcesi en az 1 bağımsız değişken gerektirir ...
user2054927

40
@ user2054927 Alt sorgu satır içermiyorsa son sorgu doğru şekilde satır döndürmez - bu konuda tehlikeli bir şey yoktur!
Tony Andrews,

En iyi cevap.
Aminadav Glickshtein

81

Dayanarak kural optimizer :

  • EXISTS, INalt sorgu sonuçları çok büyük olduğunda çok daha hızlıdır .
  • IN, EXISTSalt sorgu sonuçları çok küçük olduğunda daha hızlıdır .

Dayanarak maliyet optimizer :

  • Fark yok.

21
Argümanınızın kanıtı? IN'in EXISTS'ten daha hızlı olacağını sanmıyorum!
Nawaz

22
@Nawaz IN'in neden EXISTS'ten daha yavaş olduğuna dair kanıtlar nelerdir?
ceving

2
Kötü uygulanmış sorgu iyileştirici? Ben böyle bir şey gibi görünüyor (tam olarak bu durum olmasa da) belirli bir
RDBM'lerde

1
EXISTS, her zaman bir BIT / Boolean türünden daha büyük olan dizeleri veya değerleri karşılaştırmaktan her zaman daha hızlı olan Boole değerlerini döndürür. IN, Boole karşılaştırması olabilir veya olmayabilir. Programlama stabilite için (ACID'in bir parçası) EXPLICIT kullanımını tercih ettiğinden, genellikle EXISTS tercih edilir.
clifton_h

2
Bu neden bu kadar çok kez onaylandı? Bu varsayım temelli ifadenin genel olarak doğru olması için kesinlikle hiçbir neden yoktur.
Lukas Eder

40

Onların ne yaptığını bildiğinizi varsayıyorum ve bu nedenle farklı şekilde kullanıldığını, bu yüzden sorunuzu şu şekilde anlayacağım: Ne zaman EXISTS yerine IN kullanmak için SQL'i yeniden yazmak iyi bir fikir olur, ya da tam tersi.

Bu adil bir varsayım mı?


Düzenleme : Ben soruyorum nedeni birçok durumda bir EXISTS kullanmak yerine IN dayalı bir SQL yeniden yazabilirsiniz ve tersi ve bazı veritabanı motorları için, sorgu eniyileyici iki farklı davranır.

Örneğin:

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

şu şekilde yeniden yazılabilir:

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

veya bir birleştirme ile:

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

Yani sorum hala duruyor, orijinal poster IN ve EXISTS'in ne yaptığını ve dolayısıyla nasıl kullanılacağını merak ediyor mu, yoksa EXISTS'i kullanmak için IN'yi kullanarak bir SQL'in yeniden yazılmasının mı yoksa tam tersinin iyi bir fikir mi olacağını soruyor mu?


12
OP'yi bilmiyorum, ama bu sorunun cevabını istiyorum! Kimlik yerine bir alt sorgu ile IN yerine EXISTS'i ne zaman kullanmalıyım?
Roy Tinker

8
içinde, JOINbirDISTINCT
Jaider

4
büyük gösteri, ama hemen hemen soru cevapsız bırakın
Junchen Liu

28
  1. EXISTSINalt sorgu sonuçlarının çok büyük olduğundan çok daha hızlıdır . alt sorgu sonuçlarının çok küçük olduğundan
    INdaha hızlıdır EXISTS.

    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. Sorgu 1

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

    Sorgu 2

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

    Varsa t1sizin id boş değere sahiptir ardından Sorgu 1 bunları bulacaksınız, ancak Sorgu 2 boş parametrelerini bulamıyorum.

    Yani INhiçbir şeyi null ile karşılaştıramazsınız, bu yüzden null için hiçbir sonucu yoktur, ancak EXISTSher şeyi null ile karşılaştırabilir.


Bu cevap Tom Kite'ın duygularının makul bir özetidir ( asktom.oracle.com/pls/asktom/… )
Jeromy Fransızca

Bu cevabın yeterince adil olan sezgiye dayandığını düşünüyorum. Ancak evrensel olarak doğru olamaz. Örneğin, her iki eşdeğer SQL sorgusunu aynı QUEL sorgusu olarak ayrıştıracak olan Ingres için neredeyse kesinlikle doğru değildir , aynı şeyi birden çok yol yazmak söz konusu olduğunda SQL'in - ahem - 'zenginliği' yoktur.
oneday

Bu 2 sorgu yalnızca t2.id öğesi "NOT NULL" olarak tanımlanırsa mantıksal olarak eşdeğerdir. Tablo tanımında herhangi bir bağımlılığa sahip olmayan denkliği vermek için 2. sorgu "SELECT t1. * T1 T1 NEREDEN OLMADI (t2.id'den t2.id boş değil t2'den seçin )"
David דודו Markovitz

16

INİşleci kullanıyorsanız, SQL motoru iç sorgudan getirilen tüm kayıtları tarar. Öte yandan, kullanırsak EXISTS, SQL motoru bir eşleşme bulur bulmaz tarama işlemini durduracaktır.


10

IN sadece eşitlik ilişkilerini (veya öncesinde NOT ile eşitsizliği ) destekler. =
Any / = some ile eşanlamlıdır , örn.

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

EXISTS , IN kullanılarak ifade edilemeyen değişken ilişki türlerini destekler , örn.

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 || '℅'
                  )
;

Ve farklı bir notta -

İddiaya göre EXISTS ve IN arasındaki performans ve teknik farklılıklar , belirli satıcının uygulamalarından / sınırlamalarından / hatalarından kaynaklanabilir, ancak çoğu zaman, veritabanlarının iç kısımlarının anlaşılmaması nedeniyle oluşturulan mitlerden başka bir şey değildir.

Tabloların tanımı, istatistikleri 'doğruluğu, veritabanı yapılandırması ve optimize edicinin sürümü, yürütme planı ve dolayısıyla performans metrikleri üzerinde etkilidir.


Performans hakkındaki yorumunuz için oy verin: belirli bir DBMS'ye odaklanmadan, neyin en iyi çalıştığını belirlemenin optimize ediciye bağlı olduğunu varsaymalıyız.
Manngo

9

ExistsAnahtar kelime doğru veya yanlış değerlendirir, ancak INkarşılık gelen alt sorgu sütunundaki tüm değer karşılaştırmak anahtar sözcük. Bir diğeri Select 1ile kullanmak olabilir Existskomuta. Misal:

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

Ancak INdaha az verimli ve Existsdaha hızlıdır.


5

Bence,

  • EXISTSsorgusunun sonuçlarını başka bir alt sorgu ile eşleştirmeniz gerektiğidir. SubQuery sonuçlarının eşleştiği 1 numaralı sorgu sonuçlarının alınması gerekir. Bir Katıl Tür .. Örn. 2 numaralı sipariş tablosunu da veren müşteriler tablosu 1'i seçin

  • IN, belirli bir sütunun değerinin INbir liste (1,2,3,4,5) içerdiğini almaktır. Eg Aşağıdaki kod kodlarında yer alan müşterileri seçin, yani zip_code değerleri (....) listesinde yer alır.

Ne zaman diğerinin üzerinde kullanılır ... uygun şekilde okunduğunu hissettiğinizde (Niyet daha iyi iletişim kurar).


4

Fark burada yatıyor:

select * 
from abcTable
where exists (select null)

Yukarıdaki sorgu tüm kayıtları döndürür, bir diğeri boş döner.

select *
from abcTable
where abcTable_ID in (select null)

Bir deneyin ve çıktıyı gözlemleyin.


1
Hmmm ... Hata: [SQL0104] Belirteç) geçerli değil. Her iki durumda da. Belirli bir RDBMS mi alıyorsunuz?
jmarkmurphy

3

Bir alt sorgu bir NULLdeğer döndürdüğünde bildiklerime göre tüm ifade olur NULL. Bu durumlarda EXITSanahtar kelimeyi kullanıyoruz . Alt sorgulardaki belirli değerleri karşılaştırmak istiyorsak, INanahtar kelimeyi kullanıyoruz .


3

Hangisinin daha hızlı olduğu, iç sorgu tarafından getirilen sorgu sayısına bağlıdır:

  • İç sorgunuz binlerce satır getirildiğinde, EXIST daha iyi bir seçim olacaktır
  • İç sorgunuz birkaç satır aldığında, IN daha hızlı olacaktır

EXIST, doğru veya yanlış olarak değerlendirir ancak IN çoklu değeri karşılaştırır. Kaydın var olup olmadığını bilmiyorsanız, EXIST'i seçmelisiniz


3

Bunun nedeni, EXISTS operatörünün “en az bulunan” prensibine göre çalışmasıdır. True değerini döndürür ve en az bir eşleşen satır bulunduğunda tabloyu taramayı durdurur.

Diğer taraftan, IN işleci bir alt sorgu ile birleştirildiğinde, MySQL önce alt sorguyu işlemeli ve sonra tüm sorguyu işlemek için alt sorgunun sonucunu kullanmalıdır.

Genel kural, alt sorgu büyük miktarda veri içeriyorsa, EXISTS operatörünün daha iyi bir performans sağlamasıdır.

Ancak, alt sorgudan döndürülen sonuç kümesi çok küçükse, IN işleci kullanan sorgu daha hızlı çalışır.




0

Bir alt sorgu birden fazla değer döndürürse, dış sorguyu yürütmeniz gerekebilir - koşulda belirtilen sütundaki değerler alt sorgunun sonuç kümesindeki herhangi bir değerle eşleşiyorsa. Bu görevi gerçekleştirmek için inanahtar kelimeyi kullanmanız gerekir .

Bir kayıt kümesinin olup olmadığını kontrol etmek için bir alt sorgu kullanabilirsiniz. Bunun için, existsmaddeyi bir alt sorgu ile kullanmanız gerekir . existsAnahtar kelime daima doğru veya yanlış değerini döndürür.


0

Bunun basit bir cevabı olduğuna inanıyorum. Neden bu işlevi sistemlerinde geliştiren insanlardan kontrol etmiyorsunuz?

Bir MS SQL geliştiricisiyseniz, doğrudan Microsoft'tan gelen yanıt.

IN:

Belirtilen bir değerin alt sorgudaki veya listedeki herhangi bir değerle eşleşip eşleşmediğini belirler.

EXISTS:

Satırların varlığını sınamak için bir alt sorgu belirtir.



-1

EXISTS Performansta IN'den Daha Hızlıdır. Filtre ölçütlerinin çoğu alt sorgudaysa IN kullanmak daha iyidir ve Filtre ölçütlerinin çoğu ana sorgudaysa EXISTS kullanmak daha iyidir.


Bu iddia gerçekten hiçbir kanıtla desteklenmiyor, değil mi?
Lukas Eder

-2

IN işleci kullanıyorsanız, SQL motoru iç sorgudan getirilen tüm kayıtları tarar. Öte yandan EXISTS kullanıyorsak, SQL motoru bir eşleşme bulur bulmaz tarama işlemini durduracaktır.


@ziggy açıklıyor mu? Kabul edilen cevabın da söylediği bu. ZORUNLU her kayıt kontrol, var sadece bir bulur bulur durduramaz.
Ben Thurley

Hayır, doğru değil. INve EXISTSeşdeğer olabilir ve birbirlerine dönüştürülebilir.
Lukas Eder
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.