DALAM vs ATAU dalam SQL WHERE Clause

150

Ketika berhadapan dengan database besar, yang berkinerja lebih baik, INatau ORdalam SQL Where-clause?

Apakah ada perbedaan tentang cara mereka dieksekusi?

felix
sumber
Dugaan pertama saya adalah ATAU berkinerja lebih baik, kecuali mesin SQL mengubah IN menjadi ATAU di belakang layar. Pernahkah Anda melihat rencana kueri dari keduanya?
Raj
Kemungkinan duplikat kinerja MYSQL OR vs IN
Steve Chambers

Jawaban:

170

Saya berasumsi Anda ingin mengetahui perbedaan kinerja antara yang berikut:

WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'

Menurut manual untuk MySQL jika nilainya konstan INmengurutkan daftar dan kemudian menggunakan pencarian biner. Saya akan membayangkan bahwa ORmengevaluasi mereka satu per satu tanpa urutan tertentu. Jadi INlebih cepat dalam beberapa keadaan.

Cara terbaik untuk mengetahuinya adalah dengan membuat profil pada database Anda dengan data spesifik Anda untuk melihat mana yang lebih cepat.

Saya mencoba keduanya pada MySQL dengan 10.00000 baris. Ketika kolom diindeks tidak ada perbedaan kinerja yang jelas - keduanya hampir instan. Ketika kolom tidak diindeks saya mendapat hasil ini:

SELECT COUNT(*) FROM t_inner WHERE val IN (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
1 row fetched in 0.0032 (1.2679 seconds)

SELECT COUNT(*) FROM t_inner WHERE val = 1000 OR val = 2000 OR val = 3000 OR val = 4000 OR val = 5000 OR val = 6000 OR val = 7000 OR val = 8000 OR val = 9000;
1 row fetched in 0.0026 (1.7385 seconds)

Jadi dalam hal ini metode menggunakan OR sekitar 30% lebih lambat. Menambahkan lebih banyak istilah membuat perbedaan lebih besar. Hasil dapat bervariasi pada basis data lain dan pada data lain.

Mark Byers
sumber
20
Jika optimizer bernilai garam, mereka harus melakukan hal yang sama.
Janick Bernet
27
@inflagranti: Sayangnya tidak ada optimizer yang sempurna. Pengoptimal adalah program yang sangat kompleks dan setiap implementasi akan memiliki kekuatan dan kelemahannya sendiri. Inilah sebabnya saya katakan Anda harus membuat profil pada implementasi tertentu. Saya membayangkan bahwa struktur ekstra dari INmetode ini membuatnya lebih mudah untuk dioptimalkan daripada sejumlah ORklausa yang mungkin terkait . Saya akan terkejut jika ada mesin di mana ORmetode ini lebih cepat, tetapi saya tidak terkejut bahwa ada kalanya OR lebih lambat.
Mark Byers
2
@MarkByers Tidak bisakah pengoptimal selalu mengganti beberapa ORdengan IN?
tymtam
36

Cara terbaik untuk mengetahuinya adalah dengan melihat Rencana Eksekusi.


Saya mencobanya dengan Oracle , dan itu persis sama.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );

Meskipun kueri menggunakan IN, Rencana Eksekusi mengatakan bahwa ia menggunakan OR:

--------------------------------------------------------------------------------------    
| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |    
--------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT  |                  |     8 |  1416 |   163   (2)| 00:00:02 |    
|*  1 |  TABLE ACCESS FULL| PERFORMANCE_TEST |     8 |  1416 |   163   (2)| 00:00:02 |    
--------------------------------------------------------------------------------------    

Predicate Information (identified by operation id):                                       
---------------------------------------------------                                       

   1 - filter("OBJECT_NAME"='DBMS_LOB' OR "OBJECT_NAME"='DBMS_REGISTRY' OR                
              "OBJECT_NAME"='DBMS_STANDARD')                                              
Peter Lang
sumber
1
Apa yang terjadi di Oracle jika Anda memiliki lebih dari 3 nilai yang Anda uji? Apakah Anda tahu jika Oracle tidak dapat melakukan optimasi pencarian biner yang sama dengan MySQL atau apakah itu melakukan keduanya?
Mark Byers
2
@ Markus Byers: Saya mencoba permintaan yang sama dengan 10 nilai, masih hasilnya sama. Perhatikan, bahwa pengoptimal menggunakan nilai saya dalam urutan abjad. Saya tidak akan terkejut jika Oracle melakukan beberapa optimasi internal dari filter itu ...
Peter Lang
5
Oracle juga memiliki INLIST ITERATORoperasi, yang akan dipilih jika ada indeks yang bisa digunakan. Namun, ketika saya mencobanya, keduanya INdan ORberakhir dengan rencana eksekusi yang sama.
Cheran Shunmugavel
7

Operator OR membutuhkan proses evaluasi yang jauh lebih kompleks daripada konstruksi IN karena memungkinkan banyak kondisi, tidak hanya sama seperti IN.

Berikut ini adalah apa yang dapat Anda gunakan dengan ATAU tetapi yang tidak kompatibel dengan IN: lebih besar. lebih besar atau sama, lebih sedikit, lebih sedikit atau sama dengan, LIKE dan beberapa lagi seperti oracle REGEXP_LIKE. Selain itu pertimbangkan bahwa kondisinya mungkin tidak selalu membandingkan nilai yang sama.

Untuk pengoptimal kueri, lebih mudah untuk mengelola operator IN karena hanya konstruk yang mendefinisikan operator OR pada beberapa kondisi dengan = operator pada nilai yang sama. Jika Anda menggunakan operator OR, pengoptimal mungkin tidak menganggap bahwa Anda selalu menggunakan operator = pada nilai yang sama dan, jika tidak melakukan elaborasi yang lebih dalam dan jauh lebih kompleks, mungkin bisa mengecualikan bahwa mungkin hanya ada = operator untuk nilai yang sama pada semua kondisi yang terlibat, dengan konsekuensinya menghalangi metode pencarian yang dioptimalkan seperti pencarian biner yang telah disebutkan.

[EDIT] Mungkin pengoptimal mungkin tidak menerapkan proses evaluasi IN yang dioptimalkan, tetapi ini tidak mengecualikan bahwa sekali saja hal itu bisa terjadi (dengan pemutakhiran versi basis data). Jadi, jika Anda menggunakan operator ATAU yang diuraikan elaborasi tidak akan digunakan dalam kasus Anda.

Alessandro Rossi
sumber
6

Saya pikir oracle cukup pintar untuk mengubah yang kurang efisien (mana pun itu) menjadi yang lain. Jadi saya pikir jawabannya lebih tergantung pada keterbacaan masing-masing (di mana saya pikir itu INjelas menang)

soulmerge
sumber
2

ORmasuk akal (dari sudut pandang keterbacaan), ketika ada nilai yang lebih sedikit untuk dibandingkan. INsangat berguna esp. ketika Anda memiliki sumber dinamis, yang Anda inginkan nilainya dibandingkan.

Alternatif lain adalah menggunakan JOINtabel sementara.
Saya tidak berpikir kinerja harus menjadi masalah, asalkan Anda memiliki indeks yang diperlukan.

shahkalpesh
sumber
-2

Saya melakukan query SQL dalam sejumlah besar OR (350). Postgres melakukannya 437.80ms .

Gunakan ATAU

Sekarang gunakan IN:

Gunakan IN

23,18 ms

pengguna3003962
sumber
4
Itu bukan hal yang sama, karena Anda telah menggunakan subquery untuk klausa IN.
gliljas