MYSQL VEYA veya IN performansı


180

Aşağıdakiler arasındaki performans açısından herhangi bir fark olup olmadığını merak ediyorum

SELECT ... FROM ... WHERE someFIELD IN(1,2,3,4)

SELECT ... FROM ... WHERE someFIELD between  0 AND 5

SELECT ... FROM ... WHERE someFIELD = 1 OR someFIELD = 2 OR someFIELD = 3 ... 

veya MySQL SQL derleyicileri kod optimize aynı şekilde optimize edecek?

EDIT: yorumlarda belirtilen nedenle 's AND' olarak değiştirildi OR.


Ben de bu şeyi araştırıyorum, ama bazı ifadeler karşısında IN s I could say that it can also be converted to UNIONsorgu optimize etmek için OR`s yerine önerilen OR s satır dönüştürülecektir .
Jānis Gruzis

Yanıtlar:


249

Bunu kesin olarak bilmem gerekiyordu, bu yüzden her iki yöntemi de karşılaştırdım. Sürekli INolarak kullanmaktan çok daha hızlı buldum OR.

"Fikirlerini" veren insanlara inanmayın, bilim tamamen test ve kanıtla ilgilidir.

Ben 1000x eşdeğer sorguları bir döngü koştu (tutarlılık için, kullandım sql_no_cache):

IN: 2.34969592094s

OR: 5.83781504631s

Güncelleme:
(Orijinal test için kaynak kodum yok, 6 yıl önce olduğu gibi, bu testle aynı aralıkta bir sonuç döndürüyor olsa da)

Bunu test etmek için bazı örnek kodlar istendiğinde, mümkün olan en basit kullanım örneği aşağıdadır. Sözdizimi sadeliği için Eloquent kullanarak, ham SQL eşdeğeri aynı işlemi yürütür.

$t = microtime(true); 
for($i=0; $i<10000; $i++):
$q = DB::table('users')->where('id',1)
    ->orWhere('id',2)
    ->orWhere('id',3)
    ->orWhere('id',4)
    ->orWhere('id',5)
    ->orWhere('id',6)
    ->orWhere('id',7)
    ->orWhere('id',8)
    ->orWhere('id',9)
    ->orWhere('id',10)
    ->orWhere('id',11)
    ->orWhere('id',12)
    ->orWhere('id',13)
    ->orWhere('id',14)
    ->orWhere('id',15)
    ->orWhere('id',16)
    ->orWhere('id',17)
    ->orWhere('id',18)
    ->orWhere('id',19)
    ->orWhere('id',20)->get();
endfor;
$t2 = microtime(true); 
echo $t."\n".$t2."\n".($t2-$t)."\n";

1482080514.3635
1482080517.3713
3.0078368186951

$t = microtime(true); 
for($i=0; $i<10000; $i++): 
$q = DB::table('users')->whereIn('id',[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])->get(); 
endfor; 
$t2 = microtime(true); 
echo $t."\n".$t2."\n".($t2-$t)."\n";

1482080534.0185
1482080536.178
2.1595389842987


21
Bu testlerde hangi indeksler kullanıldı?
eggyal

5
Ben de sorguları optimize ve INifade bir yaklaşık% 30 daha hızlı olduğunu öğrendim OR.
Timo002

12
Do not believe people who give their "opinion"% 100 haklısın, Stack Overflow ne yazık ki onlarla dolu
elipoultorak

7
Performans nedeni (MariaDB (bir MySQL yeni serbest şube) dokümanlarından alıntılar): => sütununuz tamsayı ise, tamsayıları daReturns 1 if expr is equal to any of the values in the IN list, else returns 0. If all values are constants, they are evaluated according to the type of expr and sorted. The search for the item then is done using a binary search. This means IN is very quick if the IN value list consists entirely of constants . Otherwise, type conversion takes place according to the rules described at Type Conversion, but applied to all the arguments.IN
iletin

10
'Fikirlerini veren insanlara inanmayın ' şeklinde bir sonuç olarak : Bu rakamları elde etmek için kullanılan senaryoları, tabloları ve indeksleri içermeden performans rakamları sağlamak onları doğrulanamaz kılar. Bu itibarla, rakamlar bir "görüş" kadar iyidir.
Hayal Kırıklığı

67

Gelecekte Google çalışanları için de bir test yaptım. Toplam getirilen sonuç sayısı 10000 üzerinden 7264

SELECT * FROM item WHERE id = 1 OR id = 2 ... id = 10000

Bu sorgu 0.1239saniyeler aldı

SELECT * FROM item WHERE id IN (1,2,3,...10000)

Bu sorgu 0.0433saniyeler aldı

IN 3 kat daha hızlı OR


15
Hangi MySQL motoru idi ve iki sorgu arasındaki MySQL arabelleklerini ve OS dosya önbelleklerini temizlediniz mi?
dabest1

2
Testiniz dar bir kullanım senaryosudur. Sorgu, verilerin% 72'sini döndürür ve dizinlerden yararlanma olasılığı düşüktür.
Hayal Kırıklığı

Bahse girerim çoğu zaman sorguyu tüketiyor, ayrıştırıyordu ve sorgu planlıyordu. Bu kesinlikle göz önünde bulundurulması gereken bir husustur: 10k VEYA ifadeleri ORkullanacaksanız, bunu yalnızca şu ifadeyle ifade eden çok sayıda gereksiz metne sahip olursunuz: mümkün olan en kompakt ifadeyi kullanmak için en iyisi.
bishop

18

Kabul edilen cevap nedeni açıklamıyor.

Aşağıda Yüksek Performanslı MySQL, 3. Baskıdan alıntılanmıştır.

Birçok veritabanı sunucusunda, IN () işlevi birden çok OR deyiminin eş anlamlısıdır, çünkü ikisi mantıksal olarak eşdeğerdir. IN () listesindeki değerleri sıralayan ve bir değerin listede olup olmadığını görmek için hızlı bir ikili arama kullanan MySQL'de böyle değildir. Bu, liste boyutunda O (Log n) iken, eşdeğer OR cümleleri dizisi liste boyutunda O (n) 'dir (yani, büyük listeler için çok daha yavaş)


Belirli bir veritabanı nedeni fantastik referans. Güzel!
Joshua Pinter

Mükemmel ve noktaya
gaurav9620

16

BETWEEN dönüştürülmesi gerektiğinden daha hızlı olacağını düşünüyorum:

Field >= 0 AND Field <= 5

Anladığım kadarıyla bir IN zaten bir sürü OR ifadesine dönüştürülecek. IN değeri kullanım kolaylığıdır. (Her sütun adını birden çok kez yazmak zorunda kalmanız ve mevcut mantıkla kullanımı kolaylaştırır - IN bir deyim olduğu için AND / OR önceliği hakkında endişelenmenize gerek yoktur. bir koşul olarak değerlendirildiğinden emin olmak için onları parantez içine aldığınızdan emin olun.)

Sorunuzun tek cevabı, SORULARINIZI PROFİL ETMEKTİR . O zaman kendi durumunuzda neyin en iyi olduğunu bilirsiniz.


İstatistiksel olarak, Arasında aralık dizini tetikleme şansı vardır. IN () bu ayrıcalığa sahip değil. Ama evet, plaj haklı: Bir endeksin kullanılıp kullanılmadığını ve hangisinin kullanıldığını bilmek için isteğinizi profillemeniz GEREKİR. MySQL optimizatörünün ne seçeceğini tahmin etmek gerçekten zor.
Savageman

"Bir IN'nin zaten bir sürü OR ifadesine dönüştürüleceğini anlıyorum." bunu nerede okudun? Ben O (1) arama yapmak için bir hashmap koymak beklenir.
Ztyx

IN'nin OR'ye dönüştürülmesi, SQLServer'ın nasıl işlediğidir (veya en azından değişti - şimdi değişmiş olabilir, yıllardır kullanmamış olabilir). MySQL'in bunu yaptığına dair herhangi bir kanıt bulamadım.
2014

4
Bu cevap doğrudur, arasında "1 <= film_id <= 5" e çevrilir. Diğer iki çözelti tek bir aralıkta katlanmaz. Burada OPTIMIZER TRACE kullanarak bunu gösteren bir blog yazısı var: tocker.ca/2015/05/25/…
Morgan Tocker

13

Ne yaptığınıza bağlıdır; aralık ne kadar geniştir, veri türü nedir (örneğinizin sayısal bir veri türü kullandığını biliyorum ancak sorunuz birçok farklı veri türü için de geçerli olabilir).

Bu, sorguyu her iki şekilde de yazmak istediğiniz bir örnektir; Çalıştırın ve ardından yürütme farklarını bulmak için EXPLAIN kullanın.

Eminim bunun somut bir cevabı var ama pratik olarak, verilen sorumun cevabını bu şekilde çözerdim.

Bu biraz yardımcı olabilir: http://forge.mysql.com/wiki/Top10SQLPerformanceTips

Saygılarımızla,
Frank


2
Bu seçilen cevap olmalıdır.
Jon z

3
Bağlantı bayat - sanırım bu eşdeğer olabilir mi? wikis.oracle.com/pages/viewpage.action?pageId=27263381 (teşekkürler Oracle
;-P

1
Eşdeğer sayfada şöyle diyor: "Dizine alınmış alanları seçerken IN (...) kullanmaktan kaçının, SELECT sorgusunun performansını öldürür." - Bunun neden olduđuna dair bir fikrin var mý?
jorisw


7

Sunseeker'ın gözlem için bir açıklama MySQL aslında tüm statik değerler ve düz OR alternatif daha verimli ikili arama kullanarak değerleri IN deyiminde sıralamak olduğunu düşünüyorum. Bunu nerede okuduğumu hatırlayamıyorum, ama sunseeker'in sonucu bir kanıt gibi görünüyor.


4

Tam güvenli olduğunu düşündüğünüzde ...

Değeriniz nedir eq_range_index_dive_limit? Özellikle, INmaddede daha fazla veya daha az öğe var mı?

Bu bir Benchmark içermeyecek, ancak iç çalışmalara biraz bakacaktır. Neler olup bittiğini görmek için bir araç kullanalım - Optimizer Trace.

Sorgu: SELECT * FROM canada WHERE id ...

Bir ile OR3 değerlerin , iz parçası gibi görünür:

       "condition_processing": {
          "condition": "WHERE",
          "original_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(multiple equal(296172, `canada`.`id`) or multiple equal(295093, `canada`.`id`) or multiple equal(293626, `canada`.`id`))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "293626 <= id <= 293626",
                      "295093 <= id <= 295093",
                      "296172 <= id <= 296172"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

ICP'nin nasıl verildiğine dikkat edin ORs. Bu ,OR dönüştürülmediğini INve InnoDB'nin =ICP aracılığıyla bir sürü test gerçekleştireceğini ima ediyor . (MyISAM'ı dikkate almaya değeceğini düşünmüyorum.)

(Bu Percona'nın 5.6.22-71.0 günlüğüdür; idikincil bir dizindir .)

Şimdi birkaç değer içeren IN () için

eq_range_index_dive_limit= 10; 8 değer vardır.

        "condition_processing": {
          "condition": "WHERE",
          "original_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "293626 <= id <= 293626",
                      "295093 <= id <= 295093",
                      "295573 <= id <= 295573",
                      "295588 <= id <= 295588",
                      "295810 <= id <= 295810",
                      "296127 <= id <= 296127",
                      "296172 <= id <= 296172",
                      "297148 <= id <= 297148"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

Bunun INdönüşüme dönüşmediğini unutmayın OR.

Yan not: Sabit değerlerin sıralandığına dikkat edin . Bu iki şekilde faydalı olabilir:

  • Daha az atlayarak, tüm değerlere ulaşmak için daha iyi önbellekleme, daha az G / Ç olabilir.
  • İki benzer sorgu ayrı bağlantılardan geliyorsa ve işlem yapıyorsa, çakışan listeler nedeniyle kilitlenme yerine gecikme alma olasılığı daha yüksektir.

Son olarak, birçok değer içeren IN ()

      {
        "condition_processing": {
          "condition": "WHERE",
          "original_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "291752 <= id <= 291752",
                      "291839 <= id <= 291839",
                      ...
                      "297196 <= id <= 297196",
                      "297201 <= id <= 297201"
                    ],
                    "index_dives_for_eq_ranges": false,
                    "rows": 111,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

Yan not: İzin büyük olması nedeniyle buna ihtiyacım vardı:

@@global.optimizer_trace_max_mem_size = 32222;

3

VEYA en yavaş olacaktır. IN veya BETWEEN'in daha hızlı olup olmadığı verilerinize bağlı olacaktır, ancak BETWEEN'in normalde daha hızlı olmasını beklerim, çünkü basitçe bir dizinden bir aralık alabilir (someField'in dizine eklendiği varsayılarak).


3

MySQL 5.6 @SQLFiddle kullanan 6 sorgunun ayrıntıları aşağıdadır

Özetle 6 sorgu bağımsız olarak indekslenmiş sütunları kapsamaktadır ve veri tipi başına 2 sorgu kullanılmıştır. Tüm sorgular, kullanılan IN () veya OR'lerden bağımsız olarak bir dizin kullanılmasına neden oldu.

        |   ORs      |   IN()
integer | uses index | uses index
date    | uses index | uses index
varchar | uses index | uses index

Gerçekten VEYA hiçbir endeks kullanılabilir anlamına gelir yapılan ifadeleri reddetmek istedim. Bu doğru değil. Dizinler, aşağıdaki örneklerde gösterilen 6 sorgu olarak OR kullanılarak yapılan sorgularda kullanılabilir.

Ayrıca bana öyle geliyor ki birçok kişi, IN () 'nin bir dizi OR için bir sözdizimi kısayolu olduğu gerçeğini görmezden geldi. Küçük ölçekte IN () -v- OR kullanımı arasındaki performans farklılıkları son derece (infintessinal olarak) marjinaldir.

Daha büyük ölçekte IN () kesinlikle daha uygundur, ancak eşik mantıksal olarak bir dizi OR koşulu ile eşdeğerdir. Her sorgu için durum değişikliği, böylece sorgunuzu tablolarınızda test etmek her zaman en iyisidir.

6 açıklama planının özeti, tümü "Dizin koşulunu kullanma" (sağa kaydırma)

  Query               select_type    table    type    possible_keys      key      key_len   ref   rows   filtered           Extra          
                      ------------- --------- ------- --------------- ----------- --------- ----- ------ ---------- ----------------------- 
  Integers using OR   SIMPLE        mytable   range   aNum_idx        aNum_idx    4               10     100.00     Using index condition  
  Integers using IN   SIMPLE        mytable   range   aNum_idx        aNum_idx    4               10     100.00     Using index condition  
  Dates using OR      SIMPLE        mytable   range   aDate_idx       aDate_idx   6               7      100.00     Using index condition  
  Dates using IN      SIMPLE        mytable   range   aDate_idx       aDate_idx   6               7      100.00     Using index condition  
  Varchar using OR    SIMPLE        mytable   range   aName_idx       aName_idx   768             10     100.00     Using index condition  
  Varchar using IN    SIMPLE        mytable   range   aName_idx       aName_idx   768             10     100.00     Using index condition  

SQL Keman

MySQL 5.6 Şema Kurulumu :

CREATE TABLE `myTable` (
  `id` mediumint(8) unsigned NOT NULL auto_increment,
  `aName` varchar(255) default NULL,
  `aDate` datetime,
  `aNum`  mediumint(8),
  PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;

ALTER TABLE `myTable` ADD INDEX `aName_idx` (`aName`);
ALTER TABLE `myTable` ADD INDEX `aDate_idx` (`aDate`);
ALTER TABLE `myTable` ADD INDEX `aNum_idx` (`aNum`);

INSERT INTO `myTable` (`aName`,`aDate`)
 VALUES 
 ("Daniel","2017-09-19 01:22:31")
,("Quentin","2017-06-03 01:06:45")
,("Chester","2017-06-14 17:49:36")
,("Lev","2017-08-30 06:27:59")
,("Garrett","2018-10-04 02:40:37")
,("Lane","2017-01-22 17:11:21")
,("Chaim","2017-09-20 11:13:46")
,("Kieran","2018-03-10 18:37:26")
,("Cedric","2017-05-20 16:25:10")
,("Conan","2018-07-10 06:29:39")
,("Rudyard","2017-07-14 00:04:00")
,("Chadwick","2018-08-18 08:54:08")
,("Darius","2018-10-02 06:55:56")
,("Joseph","2017-06-19 13:20:33")
,("Wayne","2017-04-02 23:20:25")
,("Hall","2017-10-13 00:17:24")
,("Craig","2016-12-04 08:15:22")
,("Keane","2018-03-12 04:21:46")
,("Russell","2017-07-14 17:21:58")
,("Seth","2018-07-25 05:51:30")
,("Cole","2018-06-09 15:32:53")
,("Donovan","2017-08-12 05:21:35")
,("Damon","2017-06-27 03:44:19")
,("Brian","2017-02-01 23:35:20")
,("Harper","2017-08-25 04:29:27")
,("Chandler","2017-09-30 23:54:06")
,("Edward","2018-07-30 12:18:07")
,("Curran","2018-05-23 09:31:53")
,("Uriel","2017-05-08 03:31:43")
,("Honorato","2018-04-07 14:57:53")
,("Griffin","2017-01-07 23:35:31")
,("Hasad","2017-05-15 05:32:41")
,("Burke","2017-07-04 01:11:19")
,("Hyatt","2017-03-14 17:12:28")
,("Brenden","2017-10-17 05:16:14")
,("Ryan","2018-10-10 08:07:55")
,("Giacomo","2018-10-06 14:21:21")
,("James","2018-02-06 02:45:59")
,("Colt","2017-10-10 08:11:26")
,("Kermit","2017-09-18 16:57:16")
,("Drake","2018-05-20 22:08:36")
,("Berk","2017-04-16 17:39:32")
,("Alan","2018-09-01 05:33:05")
,("Deacon","2017-04-20 07:03:05")
,("Omar","2018-03-02 15:04:32")
,("Thaddeus","2017-09-19 04:07:54")
,("Troy","2016-12-13 04:24:08")
,("Rogan","2017-11-02 00:03:25")
,("Grant","2017-08-21 01:45:16")
,("Walker","2016-11-26 15:54:52")
,("Clarke","2017-07-20 02:26:56")
,("Clayton","2018-08-16 05:09:29")
,("Denton","2018-08-11 05:26:05")
,("Nicholas","2018-07-19 09:29:55")
,("Hashim","2018-08-10 20:38:06")
,("Todd","2016-10-25 01:01:36")
,("Xenos","2017-05-11 22:50:35")
,("Bert","2017-06-17 18:08:21")
,("Oleg","2018-01-03 13:10:32")
,("Hall","2018-06-04 01:53:45")
,("Evan","2017-01-16 01:04:25")
,("Mohammad","2016-11-18 05:42:52")
,("Armand","2016-12-18 06:57:57")
,("Kaseem","2018-06-12 23:09:57")
,("Colin","2017-06-29 05:25:52")
,("Arthur","2016-12-29 04:38:13")
,("Xander","2016-11-14 19:35:32")
,("Dante","2016-12-01 09:01:04")
,("Zahir","2018-02-17 14:44:53")
,("Raymond","2017-03-09 05:33:06")
,("Giacomo","2017-04-17 06:12:52")
,("Fulton","2017-06-04 00:41:57")
,("Chase","2018-01-14 03:03:57")
,("William","2017-05-08 09:44:59")
,("Fuller","2017-03-31 20:35:20")
,("Jarrod","2017-02-15 02:45:29")
,("Nissim","2018-03-11 14:19:25")
,("Chester","2017-11-05 00:14:27")
,("Perry","2017-12-24 11:58:04")
,("Theodore","2017-06-26 12:34:12")
,("Mason","2017-10-02 03:53:49")
,("Brenden","2018-10-08 10:09:47")
,("Jerome","2017-11-05 20:34:25")
,("Keaton","2018-08-18 00:55:56")
,("Tiger","2017-05-21 16:59:07")
,("Benjamin","2018-04-10 14:46:36")
,("John","2018-09-05 18:53:03")
,("Jakeem","2018-10-11 00:17:38")
,("Kenyon","2017-12-18 22:19:29")
,("Ferris","2017-03-29 06:59:13")
,("Hoyt","2017-01-03 03:48:56")
,("Fitzgerald","2017-07-27 11:27:52")
,("Forrest","2017-10-05 23:14:21")
,("Jordan","2017-01-11 03:48:09")
,("Lev","2017-05-25 08:03:39")
,("Chase","2017-06-18 19:09:23")
,("Ryder","2016-12-13 12:50:50")
,("Malik","2017-11-19 15:15:55")
,("Zeph","2018-04-04 11:22:12")
,("Amala","2017-01-29 07:52:17")
;

.

update MyTable
set aNum = id
;

Sorgu 1 :

select 'aNum by OR' q, mytable.*
from mytable
where aNum = 12
OR aNum = 22
OR aNum = 27
OR aNum = 32
OR aNum = 42
OR aNum = 52
OR aNum = 62
OR aNum = 65
OR aNum = 72
OR aNum = 82

Sonuçlar :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| aNum by OR | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| aNum by OR | 22 |  Donovan | 2017-08-12T05:21:35Z |   22 |
| aNum by OR | 27 |   Edward | 2018-07-30T12:18:07Z |   27 |
| aNum by OR | 32 |    Hasad | 2017-05-15T05:32:41Z |   32 |
| aNum by OR | 42 |     Berk | 2017-04-16T17:39:32Z |   42 |
| aNum by OR | 52 |  Clayton | 2018-08-16T05:09:29Z |   52 |
| aNum by OR | 62 | Mohammad | 2016-11-18T05:42:52Z |   62 |
| aNum by OR | 65 |    Colin | 2017-06-29T05:25:52Z |   65 |
| aNum by OR | 72 |   Fulton | 2017-06-04T00:41:57Z |   72 |
| aNum by OR | 82 |  Brenden | 2018-10-08T10:09:47Z |   82 |

Sorgu 2 :

select 'aNum by IN' q, mytable.*
from mytable
where aNum IN (
            12
          , 22
          , 27
          , 32
          , 42
          , 52
          , 62
          , 65
          , 72
          , 82
          )

Sonuçlar :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| aNum by IN | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| aNum by IN | 22 |  Donovan | 2017-08-12T05:21:35Z |   22 |
| aNum by IN | 27 |   Edward | 2018-07-30T12:18:07Z |   27 |
| aNum by IN | 32 |    Hasad | 2017-05-15T05:32:41Z |   32 |
| aNum by IN | 42 |     Berk | 2017-04-16T17:39:32Z |   42 |
| aNum by IN | 52 |  Clayton | 2018-08-16T05:09:29Z |   52 |
| aNum by IN | 62 | Mohammad | 2016-11-18T05:42:52Z |   62 |
| aNum by IN | 65 |    Colin | 2017-06-29T05:25:52Z |   65 |
| aNum by IN | 72 |   Fulton | 2017-06-04T00:41:57Z |   72 |
| aNum by IN | 82 |  Brenden | 2018-10-08T10:09:47Z |   82 |

Sorgu 3 :

select 'adate by OR' q, mytable.*
from mytable
where aDate= str_to_date("2017-02-15 02:45:29",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-03-10 18:37:26",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-05-20 16:25:10",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-07-10 06:29:39",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-07-14 00:04:00",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-08-18 08:54:08",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-10-02 06:55:56",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-04-20 07:03:05",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-03-02 15:04:32",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-09-19 04:07:54",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2016-12-13 04:24:08",'%Y-%m-%d %h:%i:%s')

Sonuçlar :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| adate by OR | 47 |     Troy | 2016-12-13T04:24:08Z |   47 |
| adate by OR | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |
| adate by OR | 44 |   Deacon | 2017-04-20T07:03:05Z |   44 |
| adate by OR | 46 | Thaddeus | 2017-09-19T04:07:54Z |   46 |
| adate by OR | 10 |    Conan | 2018-07-10T06:29:39Z |   10 |
| adate by OR | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| adate by OR | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |

Sorgu 4 :

select 'adate by IN' q, mytable.*
from mytable
where aDate IN (
          str_to_date("2017-02-15 02:45:29",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-03-10 18:37:26",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-05-20 16:25:10",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-07-10 06:29:39",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-07-14 00:04:00",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-08-18 08:54:08",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-10-02 06:55:56",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-04-20 07:03:05",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-03-02 15:04:32",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-09-19 04:07:54",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2016-12-13 04:24:08",'%Y-%m-%d %h:%i:%s')
        )

Sonuçlar :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| adate by IN | 47 |     Troy | 2016-12-13T04:24:08Z |   47 |
| adate by IN | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |
| adate by IN | 44 |   Deacon | 2017-04-20T07:03:05Z |   44 |
| adate by IN | 46 | Thaddeus | 2017-09-19T04:07:54Z |   46 |
| adate by IN | 10 |    Conan | 2018-07-10T06:29:39Z |   10 |
| adate by IN | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| adate by IN | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |

Sorgu 5 :

select 'name by  OR' q, mytable.*
from mytable
where aname = 'Alan'
OR aname = 'Brian'
OR aname = 'Chandler'
OR aname = 'Darius'
OR aname = 'Evan'
OR aname = 'Ferris'
OR aname = 'Giacomo'
OR aname = 'Hall'
OR aname = 'James'
OR aname = 'Jarrod'

Sonuçlar :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| name by  OR | 43 |     Alan | 2018-09-01T05:33:05Z |   43 |
| name by  OR | 24 |    Brian | 2017-02-01T23:35:20Z |   24 |
| name by  OR | 26 | Chandler | 2017-09-30T23:54:06Z |   26 |
| name by  OR | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |
| name by  OR | 61 |     Evan | 2017-01-16T01:04:25Z |   61 |
| name by  OR | 90 |   Ferris | 2017-03-29T06:59:13Z |   90 |
| name by  OR | 37 |  Giacomo | 2018-10-06T14:21:21Z |   37 |
| name by  OR | 71 |  Giacomo | 2017-04-17T06:12:52Z |   71 |
| name by  OR | 16 |     Hall | 2017-10-13T00:17:24Z |   16 |
| name by  OR | 60 |     Hall | 2018-06-04T01:53:45Z |   60 |
| name by  OR | 38 |    James | 2018-02-06T02:45:59Z |   38 |
| name by  OR | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |

Sorgu 6 :

select 'name by IN' q, mytable.*
from mytable
where aname IN (
      'Alan'
     ,'Brian'
     ,'Chandler'
     , 'Darius'
     , 'Evan'
     , 'Ferris'
     , 'Giacomo'
     , 'Hall'
     , 'James'
     , 'Jarrod'
     )

Sonuçlar :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| name by IN | 43 |     Alan | 2018-09-01T05:33:05Z |   43 |
| name by IN | 24 |    Brian | 2017-02-01T23:35:20Z |   24 |
| name by IN | 26 | Chandler | 2017-09-30T23:54:06Z |   26 |
| name by IN | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |
| name by IN | 61 |     Evan | 2017-01-16T01:04:25Z |   61 |
| name by IN | 90 |   Ferris | 2017-03-29T06:59:13Z |   90 |
| name by IN | 37 |  Giacomo | 2018-10-06T14:21:21Z |   37 |
| name by IN | 71 |  Giacomo | 2017-04-17T06:12:52Z |   71 |
| name by IN | 16 |     Hall | 2017-10-13T00:17:24Z |   16 |
| name by IN | 60 |     Hall | 2018-06-04T01:53:45Z |   60 |
| name by IN | 38 |    James | 2018-02-06T02:45:59Z |   38 |
| name by IN | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |

2

Aynı olduklarına bahse girerim, aşağıdakileri yaparak bir test yapabilirsiniz:

"in (1,2,3,4)" üzerine 500 kez dönüp ne kadar sürdüğünü görün. "= 1 veya = 2 veya = 3 ..." sürümünün 500 kez üzerine gelip ne kadar sürdüğünü görüyoruz.

someField bir dizinse ve tablonuz büyükse daha hızlı olabilir ...

SELECT ... 
    FROM ... 
        INNER JOIN (SELECT 1 as newField UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) dt ON someFIELD =newField

Yukarıdaki SQL Server'da birleştirme yöntemini denedim ve neredeyse (1,2,3,4) ile aynıdır ve her ikisi de kümelenmiş bir dizin aramasıyla sonuçlanır. MySQL'in bunları nasıl ele alacağından emin değilim.



0

Derleyicinin bu tür sorguları en iyi duruma getirme biçimi hakkında anladığım kadarıyla, IN yan tümcesini kullanmak birden çok OR yan tümcesinden daha etkilidir. BETWEEN deyiminin kullanılabileceği değerleriniz varsa, yine de daha verimlidir.


0

Field'da bir endeksiniz olduğu sürece, BETWEEN'in bir ucu hızlı bir şekilde bulmak, sonra diğerine geçmek için kullanacağını biliyorum. Bu çok verimlidir.

Gördüğüm her EXPLAIN, "IN (...)" ve "... VEYA ..." ifadelerinin birbirinin yerine kullanılabileceğini ve eşit derecede etkili olduğunu gösteriyor. Hangisini beklersiniz ki, optimize edicinin bir aralık içerip içermediğini bilmesinin bir yolu yoktur. Ayrıca, tek tek değerler üzerindeki BİRLİK TÜM SEÇİMİ ile de eşdeğerdir.


0

Başkaları tarafından açıklandığı gibi, IN sorgu performansı açısından OR'den daha iyi seçilmiştir.

VEYA koşulu olan sorgular aşağıdaki durumlarda daha uzun yürütme süresi alabilir.

  1. MySQL optimizer'ın verimli olması için başka bir indeks seçmesi durumunda (yanlış pozitif durumlarda) yürütmek için.
  2. Kayıt sayısı daha fazla ise (Jacob tarafından açıkça belirtildiği gibi)
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.