SQL WHERE Yan tümcesinde IN veya OR


150

Daha iyi performans gösteren büyük veritabanları ile uğraşırken INveya ORSQL yan Wheretümcesinde?

Yapılma şekilleri konusunda herhangi bir fark var mı?


İlk tahminim, SQL motoru IN'in sahne arkasına VEYA'ya dönüşmemesi durumunda OR'ın daha iyi performans göstermesidir. Bu ikisinin sorgu planını gördünüz mü?
Raj

Yanıtlar:


170

Aşağıdakiler arasındaki performans farkını bilmek istediğinizi varsayalım:

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

MySQL kılavuzuna göre , değerler sabitse INlisteyi sıralar ve ardından ikili bir arama kullanır. OROnları belirli bir sırayla tek tek değerlendirdiğini hayal ederdim . Yani INdaha hızlı bazı durumlarda olduğunu.

Bilmenin en iyi yolu, hangisinin daha hızlı olduğunu görmek için veritabanınızda hem belirli verilerinizle profil oluşturmaktır.

Her ikisini de 1000000 satırlı bir MySQL üzerinde denedim. Sütun endekslendiğinde, performansta fark edilebilir bir fark yoktur - her ikisi de neredeyse anındadır. Sütun dizine alınmadığında şu sonuçları aldım:

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)

Bu durumda, OR kullanan yöntem yaklaşık% 30 daha yavaştır. Daha fazla terim eklemek farkı artırır. Sonuçlar diğer veritabanlarında ve diğer verilerde değişiklik gösterebilir.


20
Optimize edici tuzuna değerse, aynı işlemi yapmalıdır.
Janick Bernet

27
@inflagranti: Ne yazık ki hiçbir iyileştirici mükemmel değildir. Doktorlar son derece karmaşık programlardır ve her uygulamanın kendine özgü güçlü ve zayıf yanları olacaktır. Bu yüzden belirli bir uygulama hakkında profil oluşturmanız gerektiğini söylüyorum. INYöntemin ekstra yapısının , muhtemelen ilgili ORmaddelerin bir demetinden daha iyi optimize etmeyi kolaylaştırdığını düşünürüm. ORYöntemin daha hızlı olduğu bir motor varsa şaşırırdım, ancak OR'in daha yavaş olduğu zamanlar olduğu için şaşırmadım.
Mark Byers

2
@MarkByers Optimize edici her zaman birden fazla ORs yerine bir IN?
timtam

36

Bunu öğrenmenin en iyi yolu İcra Planına bakmaktır.


Oracle ile denedim ve tamamen aynıydı.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

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

Sorgu kullansa da IN, Yürütme Planı şunu kullandığını söyler 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')                                              

1
Test ettiğiniz 3'ten fazla değeriniz varsa Oracle'da ne olur? Oracle'ın MySQL ile aynı ikili arama optimizasyonunu gerçekleştiremediğini veya her iki durumda da gerçekleştirdiğini biliyor musunuz?
Mark Byers

2
@ Mark Byers: Aynı değeri 10 değerle denedim, yine de aynı sonuç. Optimize edici, değerlerimi alfabetik sırayla gönderdiğini unutmayın. Oracle bu filtrenin bazı dahili optimizasyonunu yaparsa şaşırmam ...
Peter Lang

5
Oracle'ın da INLIST ITERATORkullanabileceği bir dizin olup olmadığını seçeceği bir işlem var. Yine de, bunu denedik, hem zaman INve ORaynı yürütme planı ile bitirmek.
Cheran Shunmugavel

7

OR operatörü IN yapısından çok daha karmaşık bir değerlendirme sürecine ihtiyaç duyar, çünkü sadece IN gibi eşit değildir, birçok koşula izin verir.

OR ile kullanabileceğiniz şeylere benzer, ancak IN ile uyumlu olmayanlar: daha büyük. daha büyük ya da eşit, daha az, daha az ya da eşit, GİBİ ve bazıları daha oracle REGEXP_LIKE gibi. Ayrıca, koşulların her zaman aynı değeri karşılaştırmayabileceğini düşünün.

Sorgu iyileştirici için, IN operatörünü yönetmek daha kolaydır, çünkü yalnızca OR operatörünü birden çok koşulda = operatörü ile aynı değerde tanımlayan bir yapıdır. VEYA operatörünü kullanırsanız, optimize edici her zaman = işlecini aynı değerde kullandığınızı düşünmeyebilir ve daha derin ve çok daha karmaşık bir ayrıntı vermezse, yalnızca = daha önce belirtilen ikili arama gibi optimize edilmiş arama yöntemlerinin önlenmesi ile ilgili tüm koşullarda aynı değerler için operatörler.

[EDIT] Muhtemelen bir optimize edici, optimize edilmiş IN değerlendirme işlemini uygulayamayabilir, ancak bu bir kez olabileceğini (veritabanı sürümü yükseltmesiyle) hariç tutmaz. Dolayısıyla, OR operatörünü kullanırsanız, durumunuz için optimize edilmiş ayrıntılar kullanılmaz.


6

Bence oracle daha az verimli olanı (hangisi olursa olsun) diğerine dönüştürecek kadar akıllıdır. Bu yüzden cevabın her birinin okunabilirliğine bağlı olması gerektiğini düşünüyorum (bunun INaçıkça kazandığını düşünüyorum )


2

ORkarşılaştırılacak daha az değer olduğunda (okunabilirlik açısından) mantıklıdır. INesp yararlıdır. değerlerin karşılaştırılmasını istediğiniz dinamik bir kaynağınız olduğunda.

Başka bir alternatif de JOINgeçici tablo içeren bir a kullanmaktır .
Gerekli dizinlere sahip olmanız koşuluyla performansın bir sorun olması gerektiğini düşünmüyorum.


-2

Çok sayıda OR (350) bir SQL sorgusu yaptım. Postgres bunu 437.80ms .

VEYA kullan

Şimdi IN'yi kullanın:

IN kullanın

23.18ms


4
IN yan tümcesi için bir alt sorgu kullandığınız için bu aynı şey değildir.
Ocak'ta gliljas
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.