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ı?
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ı?
Yanıtlar:
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.
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.
ORs yerine bir IN?
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')
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.
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.
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.
Çok sayıda OR (350) bir SQL sorgusu yaptım. Postgres bunu 437.80ms .

Şimdi IN'yi kullanın:

23.18ms