Kinerja MYSQL ATAU vs DALAM

180

Saya bertanya-tanya apakah ada perbedaan dalam hal kinerja antara berikut ini

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

atau akankah MySQL mengoptimalkan SQL dengan cara yang sama dengan kompiler akan mengoptimalkan kode?

EDIT: Mengubah ANDto OR's untuk alasan yang disebutkan dalam komentar.

Scott
sumber
Saya juga meneliti hal ini, tetapi bertentangan dengan beberapa pernyataan bahwa IN akan dikonversi ke deretan OR s I could say that it can also be converted to UNIONyang direkomendasikan untuk mengganti OR untuk mengoptimalkan kueri.
Jānis Gruzis

Jawaban:

249

Saya perlu tahu ini dengan pasti, jadi saya membandingkan kedua metode ini. Secara konsisten saya menemukan INjauh lebih cepat daripada menggunakan OR.

Jangan percaya orang yang memberikan "pendapat" mereka, sains adalah soal pengujian dan bukti.

Saya menjalankan loop 1000x kueri yang setara (untuk konsistensi, saya menggunakan sql_no_cache):

IN: 2.34969592094s

OR: 5.83781504631s

Pembaruan:
(Saya tidak memiliki kode sumber untuk tes asli, seperti 6 tahun yang lalu, meskipun ia mengembalikan hasil dalam kisaran yang sama dengan tes ini)

Dalam permintaan beberapa kode sampel untuk menguji ini, berikut ini adalah use case yang paling sederhana. Menggunakan Eloquent untuk kesederhanaan sintaksis, setara SQL mentah mengeksekusi yang sama.

$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

Cyril
sumber
21
Indeks apa yang digunakan dalam tes ini?
eggyal
5
Saya juga mengoptimalkan kueri dan menemukan bahwa INpernyataan itu sekitar 30% lebih cepat daripada OR.
Timo002
12
Do not believe people who give their "opinion"Anda 100% benar, sayangnya Stack Overflow penuh dengan mereka
elipoultorak
7
Alasan kinerja (mengutip dokumen MariaDB (cabang baru MySQL gratis)): => jika kolom Anda bilangan bulat, berikan bilangan bulat juga ...Returns 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
jave.web
10
Sebagai konsekuensi wajar untuk ' Jangan percaya orang yang memberikan "pendapat" mereka : Menyediakan angka kinerja tanpa menyertakan skrip, tabel, dan indeks yang digunakan untuk mendapatkan angka-angka itu membuat mereka tidak dapat diverifikasi. Dengan demikian, angkanya sama baiknya dengan "opini".
Disillusioned
67

Saya juga melakukan tes untuk Googler masa depan. Jumlah total hasil yang dikembalikan adalah 7264 dari 10.000

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

Permintaan ini membutuhkan beberapa 0.1239detik

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

Permintaan ini membutuhkan beberapa 0.0433detik

IN 3 kali lebih cepat dari OR

Ergec
sumber
15
Apa mesin MySQL itu dan apakah Anda menghapus buffer MySQL dan file cache OS di antara dua query?
dabest1
2
Tes Anda adalah kasus penggunaan yang sempit. Permintaan mengembalikan 72% dari data, dan tidak mungkin mendapat manfaat dari indeks.
Disillusioned
Saya bertaruh sebagian besar waktu itu menghabiskan permintaan, menguraikannya, dan merencanakan permintaan itu. Itu tentu pertimbangan: jika Anda akan memiliki 10k ATAU pernyataan, Anda akan memiliki banyak teks yang berlebihan hanya dengan mengekspresikannya OR: terbaik untuk menggunakan ekspresi sekecil mungkin.
Uskup
17

Jawaban yang diterima tidak menjelaskan alasannya.

Di bawah ini dikutip dari High Performance MySQL, 3rd Edition.

Di banyak server basis data, IN () hanyalah sinonim untuk beberapa klausa ATAU, karena keduanya secara logis setara. Tidak demikian halnya di MySQL, yang mengurutkan nilai dalam daftar IN () dan menggunakan pencarian biner cepat untuk melihat apakah suatu nilai ada dalam daftar. Ini adalah O (Log n) dalam ukuran daftar, sedangkan seri yang setara dari klausa OR adalah O (n) dalam ukuran daftar (yaitu, jauh lebih lambat untuk daftar besar)

Yakub
sumber
Referensi fantastis untuk alasan basis data spesifik. Bagus!
Joshua Pinter
Sempurna dan to the point
gaurav9620
16

Saya pikir BETWEEN akan lebih cepat karena harus diubah menjadi:

Field >= 0 AND Field <= 5

Ini adalah pemahaman saya bahwa IN akan dikonversi ke sekelompok pernyataan ATAU. Nilai IN adalah kemudahan penggunaan. (Menghemat karena harus mengetik setiap nama kolom beberapa kali dan juga membuatnya lebih mudah untuk digunakan dengan logika yang ada - Anda tidak perlu khawatir tentang AND / ATAU didahulukan karena IN adalah satu pernyataan. Dengan banyak pernyataan ATAU, Anda memiliki untuk memastikan Anda mengelilinginya dengan tanda kurung untuk memastikan mereka dievaluasi sebagai satu syarat.)

Satu-satunya jawaban nyata untuk pertanyaan Anda adalah PROFIL QUERIES ANDA . Maka Anda akan tahu apa yang paling berhasil dalam situasi khusus Anda.

pantai
sumber
Secara statistik, Antara memiliki peluang untuk memicu rentang indeks. IN () tidak memiliki hak istimewa ini. Tapi ya, pantai benar: Anda PERLU untuk membuat profil permintaan Anda untuk mengetahui apakah indeks digunakan dan yang mana. Sangat sulit untuk memprediksi apa yang akan dipilih oleh pengoptimal MySQL.
Savageman
"Ini adalah pemahaman saya bahwa IN akan dikonversi ke sekelompok pernyataan ATAU." Di mana Anda membaca ini? Saya berharap untuk memasukkannya ke dalam hashmap untuk membuat O (1) pencarian.
Ztyx
IN sedang dikonversi ke OR adalah bagaimana SQLServer menanganinya (atau setidaknya itu - mungkin telah berubah sekarang, belum pernah menggunakannya selama bertahun-tahun). Saya tidak dapat menemukan bukti bahwa MySQL melakukan ini.
RichardAtHome
4
Jawaban ini benar, antara dikonversi menjadi "1 <= film_id <= 5". Dua solusi lainnya tidak dilipat menjadi kondisi rentang tunggal. Saya punya posting blog yang menunjukkan ini menggunakan OPTIMIZER TRACE di sini: tocker.ca/2015/05/05/25/…
Morgan Tocker
13

Itu tergantung pada apa yang Anda lakukan; seberapa luas jangkauannya, apa tipe datanya (Saya tahu contoh Anda menggunakan tipe data numerik tetapi pertanyaan Anda juga dapat diterapkan pada banyak tipe data yang berbeda).

Ini adalah contoh di mana Anda ingin menulis kueri dua arah; membuatnya bekerja dan kemudian gunakan MENJELASKAN untuk mengetahui perbedaan eksekusi.

Saya yakin ada jawaban konkret untuk ini tetapi ini adalah bagaimana saya akan, secara praktis, mencari tahu jawaban untuk pertanyaan saya.

Ini mungkin bisa membantu: http://forge.mysql.com/wiki/Top10SQLPerformanceTips

Salam,
Frank

Frank V
sumber
2
Ini harus menjadi jawaban yang dipilih.
Jon z
3
Tautannya basi - saya pikir ini mungkin setara? wikis.oracle.com/pages/viewpage.action?pageId=27263381 (terima kasih Oracle ;-P)
ilasno
1
Pada halaman yang setara, dikatakan: "Hindari menggunakan IN (...) saat memilih pada bidang yang diindeks, Ini akan mematikan kinerja permintaan SELECT." - Adakah yang tahu mengapa itu terjadi?
jorisw
url telah kedaluwarsa
Steve Jiang
7

Saya pikir salah satu penjelasan untuk pengamatan sunseeker adalah MySQL sebenarnya mengurutkan nilai-nilai dalam pernyataan IN jika mereka semua nilai statis dan menggunakan pencarian biner, yang lebih efisien daripada alternatif polos ATAU. Saya tidak ingat di mana saya membacanya, tetapi hasil sunseeker tampaknya menjadi bukti.

pengguna658991
sumber
4

Tepat ketika Anda berpikir itu aman ...

Apa nilai Anda eq_range_index_dive_limit? Secara khusus, apakah Anda memiliki lebih banyak atau lebih sedikit item dalam INklausa?

Ini tidak akan termasuk Tolok Ukur, tetapi akan sedikit mengintip ke dalam kerja batin. Mari kita gunakan alat untuk melihat apa yang sedang terjadi - Jejak Pengoptimal.

Kueri: SELECT * FROM canada WHERE id ...

Dengan ORnilai 3 , bagian dari jejaknya terlihat seperti:

       "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"
          }
        ]

Perhatikan bagaimana ICP diberikan ORs. Ini menyiratkan bahwa ORtidak berubah menjadi IN, dan InnoDB akan melakukan banyak= tes melalui ICP. (Saya tidak merasa perlu mempertimbangkan MyISAM.)

(Ini adalah 5.6.22-71.0-log Percona; idini adalah indeks sekunder.)

Sekarang untuk IN () dengan beberapa nilai

eq_range_index_dive_limit= 10; ada 8 nilai.

        "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"
          }
        ]

Perhatikan bahwa INtampaknya tidak berubah menjadi OR.

Catatan samping: Perhatikan bahwa nilai konstan diurutkan . Ini bisa bermanfaat dalam dua cara:

  • Dengan melompat-lompat lebih sedikit, mungkin ada caching yang lebih baik, lebih sedikit I / O untuk mendapatkan semua nilai.
  • Jika dua pertanyaan serupa berasal dari koneksi terpisah, dan mereka dalam transaksi, ada peluang yang lebih baik untuk mendapatkan penundaan daripada kebuntuan karena daftar yang tumpang tindih.

Akhirnya, IN () dengan banyak nilai

      {
        "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"
          }
        ]

Catatan: Saya membutuhkan ini karena besarnya jejak:

@@global.optimizer_trace_max_mem_size = 32222;
Rick James
sumber
3

ATAU akan paling lambat. Apakah IN atau ANTARA lebih cepat akan tergantung pada data Anda, tapi saya berharap ANTARA lebih cepat secara normal karena dapat dengan mudah mengambil rentang dari indeks (dengan asumsi someField diindeks).

Greg
sumber
3

Di bawah ini adalah detail dari 6 pertanyaan menggunakan MySQL 5.6 @SQLFiddle

Singkatnya, 6 kueri mencakup kolom yang diindeks secara independen dan 2 kueri digunakan per tipe data. Semua kueri menghasilkan penggunaan indeks terlepas dari IN () atau OR yang digunakan.

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

Saya benar-benar hanya ingin menyanggah pernyataan yang dibuat ATAU berarti tidak ada indeks yang dapat digunakan. Ini tidak benar. Indeks dapat digunakan dalam kueri menggunakan OR sebagai 6 kueri dalam tampilan contoh berikut.

Juga nampak bagi saya bahwa banyak orang telah mengabaikan fakta bahwa IN () adalah jalan pintas sintaks untuk satu set OR. Pada skala kecil perbedaan kinerja antara menggunakan IN () -v- OR sangat marginal.

Meskipun pada skala yang lebih besar IN () tentu lebih nyaman, tetapi masih sama dengan serangkaian kondisi ATAU secara logis. Perubahan keadaan untuk setiap kueri sehingga menguji kueri Anda di tabel Anda selalu yang terbaik.

Ringkasan dari 6 menjelaskan rencana, semua "Menggunakan kondisi indeks" (gulir ke kanan)

  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 Fiddle

Pengaturan Skema MySQL 5.6 :

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
;

Pertanyaan 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

Hasil :

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

Pertanyaan 2 :

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

Hasil :

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

Pertanyaan 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')

Hasil :

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

Pertanyaan 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')
        )

Hasil :

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

Pertanyaan 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'

Hasil :

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

Pertanyaan 6 :

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

Hasil :

|          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 |
Used_By_Already
sumber
2

Saya yakin mereka sama, Anda dapat menjalankan tes dengan melakukan hal berikut:

loop di atas "dalam (1,2,3,4)" 500 kali dan lihat berapa lama. loop di atas versi "= 1 atau = 2 atau = 3 ..." 500 kali dan lihat berapa lama itu berjalan.

Anda juga bisa mencoba cara bergabung, jika someField adalah indeks dan meja Anda besar itu bisa lebih cepat ...

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

Saya mencoba metode bergabung di atas pada SQL Server saya dan hampir sama dengan di (1,2,3,4), dan keduanya menghasilkan pencarian indeks berkerumun. Saya tidak yakin bagaimana MySQL akan menanganinya.

KM.
sumber
2

2018 : IN (...) lebih cepat. Tetapi > = && <= bahkan lebih cepat daripada IN .

Inilah tolok ukur saya .

evilReiko
sumber
0

Dari apa yang saya mengerti tentang cara kompiler mengoptimalkan jenis pertanyaan ini, menggunakan klausa IN lebih efisien daripada beberapa klausa ATAU. Jika Anda memiliki nilai di mana klausa BETWEEN dapat digunakan, itu masih lebih efisien.

Brandon Wood
sumber
0

Saya tahu bahwa, selama Anda memiliki indeks di Field, BETWEEN akan menggunakannya untuk dengan cepat menemukan satu ujung, lalu melintasi ke yang lain. Ini paling efisien.

Setiap MENJELASKAN yang saya lihat menunjukkan "IN (...)" dan "... ATAU ..." yang dapat dipertukarkan dan sama-sama efisien. Yang Anda harapkan, karena pengoptimal tidak memiliki cara untuk mengetahui apakah mereka terdiri dari interval. Ini juga setara dengan UNION ALL SELECT pada nilai-nilai individual.

dkretz
sumber
0

Seperti yang dijelaskan oleh orang lain, IN lebih baik dipilih daripada ATAU sehubungan dengan kinerja permintaan.

Pertanyaan dengan kondisi ATAU mungkin membutuhkan waktu eksekusi lebih lama dalam kasus di bawah ini.

  1. untuk mengeksekusi jika pengoptimal MySQL memilih indeks lain untuk menjadi efisien (selama kasus positif palsu).
  2. Jika jumlah catatan lebih banyak (Seperti yang dinyatakan dengan jelas oleh Jacob)
Adithya
sumber