Perbedaan antara EXISTS dan IN dalam SQL?

443

Apa perbedaan antara EXISTSdan INklausa dalam SQL?

Kapan kita harus menggunakan EXISTS, dan kapan kita harus menggunakan IN?

Krantz
sumber

Jawaban:

224

Kata existskunci dapat digunakan dengan cara itu, tetapi sebenarnya itu dimaksudkan sebagai cara untuk menghindari penghitungan:

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

Ini sangat berguna di mana Anda memiliki ifpernyataan bersyarat, karena existsbisa jauh lebih cepat daripada count.

Yang interbaik digunakan di mana Anda memiliki daftar statis untuk dilewati:

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

Ketika Anda memiliki tabel dalam inpernyataan, lebih masuk akal untuk menggunakan join, tetapi sebagian besar itu tidak masalah. Pengoptimal kueri harus mengembalikan paket yang sama. Dalam beberapa implementasi (kebanyakan lebih tua, seperti Microsoft SQL Server 2000) inkueri akan selalu mendapatkan paket bergabung bersarang , sementara joinkueri akan menggunakan bersarang, menggabungkan atau hash yang sesuai. Implementasi yang lebih modern lebih cerdas dan dapat menyesuaikan rencana bahkan ketika indigunakan.

Keith
sumber
2
Bisakah Anda menguraikan "Ketika Anda memiliki tabel dalam pernyataan dalam, lebih masuk akal untuk menggunakan gabungan, tetapi itu tidak terlalu penting. Pengoptimal kueri akan mengembalikan paket yang sama."? Bukan bagian pengoptimal permintaan, bagian di mana Anda dapat menggunakan JOINsebagai pengganti IN.
farthVader
select * from [table] where [field] in (select [field] from [table2])mengembalikan hasil yang sama (dan rencana kueri) sebagai select * from [table] join [table2] on [table2].[field] = [table].[field].
@Sander tidak: permintaan pertama mengembalikan semua kolom dari table, sedangkan yang kedua mengembalikan semuanya dari tabledan table2. Dalam beberapa (sebagian besar yang lebih tua) database SQL inkueri akan diimplementasikan sebagai bergabung bersarang, sementara joinkueri dapat bersarang, digabung, hash, dll - apa pun yang tercepat.
Keith
2
Oke, saya seharusnya sudah menentukan kolom pada klausa pilih, tetapi Anda harus memperbarui jawaban Anda karena itu dengan jelas menyatakan bahwa pertanyaan "akan mengembalikan paket yang sama dengan cara yang sama".
existsdapat digunakan dalam pernyataan kasus, sehingga mereka dapat berguna juga yaituselect case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie
125

EXISTSakan memberi tahu Anda apakah kueri mengembalikan hasil apa pun. misalnya:

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

IN digunakan untuk membandingkan satu nilai dengan beberapa, dan dapat menggunakan nilai literal, seperti ini:

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

Anda juga dapat menggunakan hasil kueri dengan INklausa, seperti ini:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)
Matt Hamilton
sumber
3
Kueri terakhir berbahaya karena mungkin gagal jika subquery tidak memberikan hasil apa pun. klausa 'in' membutuhkan setidaknya 1 argumen ...
user2054927
40
@ user2054927 Permintaan terakhir tidak akan mengembalikan baris jika subquery tidak mengembalikan baris - tidak ada yang berbahaya tentang itu!
Tony Andrews
Jawaban terbaik
Aminadav Glickshtein
81

Berdasarkan pengoptimal aturan :

  • EXISTSjauh lebih cepat daripada IN, ketika hasil sub-permintaan sangat besar.
  • INlebih cepat daripada EXISTS, ketika hasil sub-permintaan sangat kecil.

Berdasarkan pengoptimal biaya :

  • Tidak ada perbedaan.
jackson
sumber
21
Bukti argumen Anda? Saya tidak berpikir IN akan lebih cepat dari yang ada sebelumnya!
Nawaz
22
@Nawaz Bagaimana dengan bukti mengapa IN selalu lebih lambat dari EXISTS?
ceving
2
Pengoptimal permintaan yang diimplementasikan dengan buruk? Saya telah melihat sesuatu seperti ini (walaupun tidak persis seperti situasi ini) terjadi dalam
RDBM
1
EXISTS mengembalikan nilai Boolean murni, yang selalu lebih cepat daripada harus membandingkan string atau nilai yang lebih besar dari tipe BIT / Boolean. IN mungkin merupakan perbandingan Boolean atau tidak. Karena pemrograman lebih suka penggunaan EXPLICIT untuk stabilitas (bagian dari ACID), EXIS umumnya lebih disukai.
clifton_h
2
Mengapa ini terbalik berkali-kali? Sama sekali tidak ada alasan mengapa pernyataan berbasis asumsi ini umumnya benar.
Lukas Eder
40

Saya berasumsi Anda tahu apa yang mereka lakukan, dan dengan demikian digunakan secara berbeda, jadi saya akan memahami pertanyaan Anda sebagai: Kapan ide yang baik untuk menulis ulang SQL untuk menggunakan IN daripada EXISTS, atau sebaliknya.

Apakah itu asumsi yang adil?


Sunting : Alasan saya bertanya adalah bahwa dalam banyak kasus Anda dapat menulis ulang SQL berdasarkan IN untuk menggunakan EXIS, dan sebaliknya, dan untuk beberapa mesin basis data, pengoptimal kueri akan memperlakukan keduanya secara berbeda.

Contohnya:

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

dapat ditulis ulang menjadi:

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

atau dengan bergabung:

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

Jadi pertanyaan saya masih berdiri, apakah poster asli bertanya-tanya tentang apa IN dan EXISTS, dan dengan demikian bagaimana menggunakannya, atau apakah dia bertanya apakah menulis ulang SQL menggunakan IN untuk menggunakan EXISTS sebagai gantinya, atau sebaliknya, akan menjadi ide yang baik?

Lasse V. Karlsen
sumber
12
Saya tidak tahu tentang OP, tetapi saya ingin jawaban untuk pertanyaan ini! Kapan saya harus menggunakan EXISTS dan bukannya IN dengan subquery yang mengembalikan ID?
Roy Tinker
8
di JOIN, Anda membutuhkanDISTINCT
Jaider
4
demonstrasi hebat, tetapi cukup banyak meninggalkan pertanyaan yang belum terjawab
Junchen Liu
28
  1. EXISTSjauh lebih cepat daripada INketika hasil subquery sangat besar.
    INlebih cepat daripada EXISTSketika hasil subquery sangat kecil.

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

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

    Pertanyaan 2

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

    Jika dalam t1id Anda memiliki nilai nol maka Kueri 1 akan menemukannya, tetapi Kueri 2 tidak dapat menemukan parameter nol.

    Maksud saya INtidak dapat membandingkan apa pun dengan nol, jadi tidak ada hasil untuk nol, tetapi EXISTSdapat membandingkan semuanya dengan nol.

Alireza Masali
sumber
Jawaban ini masuk akal dari sentimen Tom Kite ( asktom.oracle.com/pls/asktom/… )
Jeromy French
Saya pikir jawaban ini didasarkan pada intuisi, yang cukup adil. Tetapi itu tidak mungkin benar secara universal. Sebagai contoh, hampir pasti tidak benar untuk Ingres , yang akan mengurai kedua query SQL yang setara menjadi query QUEL yang sama, yang tidak memiliki 'ahem -' kekayaan 'SQL ketika harus menulis hal yang sama dengan berbagai cara.
onedaywhen
2 kueri ini secara logis setara jika dan hanya jika t2.id didefinisikan sebagai "NOT NULL". Untuk memberikan kesetaraan tanpa ketergantungan pada definisi tabel, kueri ke-2 harus "SELECT t1. * DARI t1 WHERE t1.id tidak dalam (SELECT t2.id FROM t2 di mana t2.id bukan nol )"
David Markודו Markovitz
16

Jika Anda menggunakan INoperator, mesin SQL akan memindai semua catatan yang diambil dari permintaan dalam. Di sisi lain jika kita menggunakan EXISTS, mesin SQL akan menghentikan proses pemindaian segera setelah menemukan kecocokan.

Jika Anda menggunakan operat IN
sumber
10

IN hanya mendukung hubungan kesetaraan (atau ketidaksetaraan ketika didahului oleh TIDAK ).
Ini adalah sinonim dari = any / = some , eg

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

EXISTS mendukung berbagai jenis hubungan, yang tidak dapat diekspresikan menggunakan IN , misalnya -

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

Dan pada nada yang berbeda -

Perbedaan kinerja dan teknis yang diduga antara EXISTS dan IN dapat terjadi akibat implementasi / batasan / bug vendor spesifik, tetapi sering kali mereka tidak lain hanyalah mitos yang diciptakan karena kurangnya pemahaman internal database.

Definisi tabel, akurasi statistik, konfigurasi basis data, dan versi pengoptimal memiliki semua dampak pada rencana eksekusi dan oleh karena itu pada metrik kinerja.

David Markודו Markovitz
sumber
Terpilih untuk komentar Anda tentang kinerja: tanpa berfokus pada DBMS tertentu, kami harus mengasumsikan bahwa tergantung pada pengoptimal untuk menentukan yang terbaik.
Manngo
9

Kata Existskunci mengevaluasi benar atau salah, tetapi INkata kunci membandingkan semua nilai dalam kolom permintaan sub yang sesuai. Satu lagi Select 1dapat digunakan dengan Existsperintah. Contoh:

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

Tetapi INkurang efisien jadi Existslebih cepat.

Arulraj.M
sumber
5

Kupikir,

  • EXISTSadalah saat Anda harus mencocokkan hasil kueri dengan subquery lain. Hasil Query # 1 harus diambil di tempat yang cocok dengan hasil SubQuery. Jenis Bergabung. Misalnya memilih tabel pelanggan # 1 yang telah menempatkan tabel pesanan # 2 juga

  • IN adalah untuk mengambil jika nilai kolom tertentu terletak INdalam daftar (1,2,3,4,5). Mis. Pilih pelanggan yang berada dalam kode pos berikut ini, yaitu nilai-nilai zip_code terletak pada daftar (....).

Kapan harus menggunakan satu di atas yang lain ... ketika Anda merasa itu membaca dengan tepat (Berkomunikasi niat lebih baik).

Gishu
sumber
4

Perbedaannya terletak di sini:

select * 
from abcTable
where exists (select null)

Kueri di atas akan mengembalikan semua catatan sementara di bawah yang satu akan kembali kosong.

select *
from abcTable
where abcTable_ID in (select null)

Cobalah dan amati hasilnya.

anak nakal
sumber
1
Hmmm ... Kesalahan: [SQL0104] Token) tidak valid. Dalam kedua kasus tersebut. Apakah Anda mengasumsikan RDBMS tertentu?
jmarkmurphy
3

Sesuai pengetahuan saya ketika subquery mengembalikan NULLnilai maka seluruh pernyataan menjadi NULL. Dalam hal ini kami menggunakan EXITSkata kunci. Jika kami ingin membandingkan nilai tertentu dalam subqueries maka kami menggunakan INkata kunci.

ram
sumber
3

Yang mana yang lebih cepat tergantung pada jumlah kueri yang diambil oleh kueri batin:

  • Ketika permintaan dalam diri Anda mengambil ribuan baris maka EXIST akan menjadi pilihan yang lebih baik
  • Saat kueri batin Anda mengambil beberapa baris, maka IN akan lebih cepat

ADA mengevaluasi benar atau salah tetapi DI membandingkan nilai ganda. Ketika Anda tidak tahu catatan itu ada atau tidak, Anda harus memilih ADA

Sumair Hussain Rajput
sumber
3

Alasannya adalah bahwa operator EXISTS bekerja berdasarkan prinsip "setidaknya ditemukan". Ini mengembalikan true dan berhenti memindai tabel sekali setidaknya satu baris yang cocok ditemukan.

Di sisi lain, ketika operator IN digabungkan dengan subquery, MySQL harus memproses subquery terlebih dahulu, dan kemudian menggunakan hasil dari subquery untuk memproses seluruh permintaan.

Aturan umum adalah bahwa jika subquery berisi sejumlah besar data, operator EXISTS memberikan kinerja yang lebih baik.

Namun, kueri yang menggunakan operator IN akan bekerja lebih cepat jika set hasil yang dikembalikan dari subquery sangat kecil.

Vipin Jain
sumber
1

Pemahaman saya adalah keduanya harus sama selama kita tidak berurusan dengan nilai NULL.

Alasan yang sama mengapa kueri tidak mengembalikan nilai untuk = NULL vs adalah NULL. http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

Adapun argumen boolean vs komparator berjalan, untuk menghasilkan boolean kedua nilai perlu dibandingkan dan itulah bagaimana jika kondisi bekerja. Jadi saya gagal untuk memahami bagaimana IN dan EXISTS berperilaku berbeda.

Ranjeeth
sumber
0

Jika subquery mengembalikan lebih dari satu nilai, Anda mungkin perlu menjalankan query luar- jika nilai dalam kolom yang ditentukan dalam kondisi cocok dengan nilai apa pun di set hasil subquery. Untuk melakukan tugas ini, Anda perlu menggunakan inkata kunci.

Anda dapat menggunakan subquery untuk memeriksa apakah ada catatan. Untuk ini, Anda perlu menggunakan existsklausa dengan subquery. Kata existskunci selalu mengembalikan nilai benar atau salah.

John
sumber
0

Saya percaya ini memiliki jawaban langsung. Mengapa Anda tidak memeriksanya dari orang yang mengembangkan fungsi itu di sistem mereka?

Jika Anda seorang pengembang MS SQL, berikut ini jawabannya langsung dari Microsoft.

IN:

Menentukan apakah nilai yang ditentukan cocok dengan nilai apa pun di subquery atau daftar.

EXISTS:

Menentukan subquery untuk menguji keberadaan baris.

Kesalahan fatal
sumber
0

Saya menemukan bahwa menggunakan kata kunci yang ada sering kali sangat lambat (itu sangat benar di Microsoft Access). Saya malah menggunakan operator bergabung dengan cara ini: harus-saya-gunakan-kata kunci-ada-di-sql

Axel Der
sumber
-1

EXISTS Lebih Cepat dalam Kinerja daripada IN. Jika sebagian besar kriteria filter dalam subquery maka lebih baik untuk menggunakan IN dan Jika sebagian besar kriteria filter dalam permintaan utama maka lebih baik menggunakan EXISTS.

Deva
sumber
Klaim itu benar-benar tidak didukung oleh bukti, bukan?
Lukas Eder
-2

Jika Anda menggunakan operator IN, mesin SQL akan memindai semua catatan yang diambil dari permintaan dalam. Di sisi lain jika kita menggunakan EXIS, mesin SQL akan menghentikan proses pemindaian segera setelah menemukan kecocokan.

Gagandeep Singh
sumber
@ziggy menjelaskan? Ini adalah apa yang dikatakan oleh jawaban yang diterima. Di HARUS memeriksa setiap catatan tunggal, ada dapat berhenti segera setelah menemukan hanya satu.
Ben Thurley
Tidak, tidak benar. INdan EXISTSdapat setara dan ditransformasikan menjadi satu sama lain.
Lukas Eder