ประสิทธิภาพของ MySQL หรือ vs IN


180

ฉันสงสัยว่ามีความแตกต่างในเรื่องการแสดงระหว่างสิ่งต่อไปนี้หรือไม่

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

หรือว่า MySQL จะปรับ SQL ให้เหมาะสมในลักษณะเดียวกับที่คอมไพเลอร์จะปรับโค้ดให้เหมาะสม

แก้ไข: เปลี่ยนAND'เพื่อOR' s ด้วยเหตุผลที่ระบุไว้ในการแสดงความคิดเห็น


ฉันยังค้นคว้าสิ่งนี้ แต่ในทางตรงกันข้ามสำหรับข้อความบางคำว่า IN จะถูกแปลงเป็นแถวของ OR s I could say that it can also be converted to UNIONซึ่งได้รับการแนะนำให้แทนที่OR หรือเพื่อเพิ่มประสิทธิภาพการค้นหา
Jānis Gruzis

คำตอบ:


249

ฉันจำเป็นต้องรู้สิ่งนี้อย่างแน่นอนดังนั้นฉันจึงทำการเปรียบเทียบทั้งสองวิธี ฉันพบว่าINจะเร็วกว่าการใช้ORอย่างมาก

อย่าเชื่อคนที่ให้ "ความเห็น" วิทยาศาสตร์เป็นเรื่องเกี่ยวกับการทดสอบและหลักฐาน

ฉันใช้คำสั่งที่เทียบเท่า 1,000x (เพื่อความสอดคล้องฉันใช้sql_no_cache):

IN: 2.34969592094s

OR: 5.83781504631 วินาที

อัปเดต:
(ฉันไม่มีซอร์สโค้ดสำหรับการทดสอบดั้งเดิมเหมือนเมื่อ 6 ปีก่อนแม้ว่ามันจะส่งคืนผลลัพธ์ในช่วงเดียวกันกับการทดสอบนี้)

ในการขอรหัสตัวอย่างเพื่อทดสอบสิ่งนี้นี่เป็นกรณีการใช้งานที่ง่ายที่สุดที่เป็นไปได้ การใช้ Eloquent เพื่อความเรียบง่ายของไวยากรณ์, SQL ดิบที่เทียบเท่าจะดำเนินการเหมือนกัน

$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
มีการใช้ดัชนีใดในการทดสอบเหล่านี้
eggyal

5
ผมยังเพิ่มประสิทธิภาพการสอบถามและพบว่าINคำสั่งเป็นประมาณ 30% ORเร็วกว่า
Timo002

12
Do not believe people who give their "opinion"คุณ 100% ถูกต้อง Stack Overflow เต็มไปด้วยโชคร้าย
elipoultorak

7
เหตุผลด้านประสิทธิภาพ (การอ้างอิง MariaDB (เอกสารใหม่ฟรีสาขา MySQL): => หากคอลัมน์ของคุณเป็นจำนวนเต็มให้ส่งจำนวนเต็มไปที่...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
ในฐานะที่เป็นข้อพิสูจน์ว่า ' อย่าเชื่อคนที่ให้ "ความเห็น" ของพวกเขา : การจัดหาตัวเลขประสิทธิภาพโดยไม่รวมสคริปต์ตารางและดัชนีที่ใช้เพื่อให้ได้ตัวเลขเหล่านั้นทำให้พวกเขาไม่สามารถพิสูจน์ได้ เช่นนี้ตัวเลขที่ดีเท่ากับ "ความคิดเห็น"
ไม่แยแส

67

ฉันได้ทำการทดสอบกับชาว Google ในอนาคตด้วย จำนวนผลลัพธ์ทั้งหมดที่ส่งคืนคือ 7264 จาก 10,000

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

แบบสอบถามนี้ใช้0.1239เวลาไม่กี่วินาที

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

แบบสอบถามนี้ใช้0.0433เวลาไม่กี่วินาที

IN เร็วกว่า 3 เท่า OR


15
เอนจิ้นของ MySQL คืออะไรและคุณล้างบัฟเฟอร์ของ MySQL และไฟล์แคชระบบปฏิบัติการระหว่างสองคำสั่งหรือไม่
dabest1

2
การทดสอบของคุณเป็นกรณีใช้งานแคบ แบบสอบถามส่งคืน 72% ของข้อมูลและไม่น่าจะได้รับประโยชน์จากดัชนี
ไม่แยแส

ฉันพนันว่าเวลาส่วนใหญ่นั้นใช้แบบสอบถามการแยกวิเคราะห์และการวางแผนแบบสอบถาม นั่นเป็นข้อพิจารณาอย่างแน่นอน: ถ้าคุณจะมีคำสั่ง 10k หรือ OR คุณจะมีข้อความซ้ำซ้อนมากมายที่แสดงด้วยOR: ดีที่สุดที่จะใช้การแสดงออกที่กะทัดรัดที่สุดเท่าที่จะทำได้
บิชอป

18

คำตอบที่ยอมรับไม่ได้อธิบายเหตุผล

ด้านล่างนี้มาจาก MySQL ประสิทธิภาพสูง, รุ่นที่ 3

ในเซิร์ฟเวอร์ฐานข้อมูลจำนวนมาก IN () เป็นเพียงคำพ้องความหมายสำหรับหลาย ๆ คำสั่งเนื่องจากทั้งสองนั้นมีเหตุผลเทียบเท่ากัน ไม่เช่นนั้นใน MySQL ซึ่งเรียงลำดับค่าในรายการ IN () และใช้การค้นหาแบบไบนารีอย่างรวดเร็วเพื่อดูว่ามีค่าอยู่ในรายการหรือไม่ นี่คือ O (Log n) ในขนาดของรายการในขณะที่ชุดคำสั่ง OR ที่เทียบเท่าคือ O (n) ในขนาดของรายการ (เช่นช้ากว่ามากสำหรับรายการขนาดใหญ่)


การอ้างอิงที่ยอดเยี่ยมกับเหตุผลฐานข้อมูลเฉพาะ ดี!
Joshua Pinter

สมบูรณ์แบบและตรงประเด็น
gaurav9620

16

ฉันคิดว่า BETWEEN จะเร็วขึ้นเนื่องจากควรเปลี่ยนเป็น:

Field >= 0 AND Field <= 5

ฉันเข้าใจว่า IN จะถูกแปลงเป็นงบ OR จำนวนมาก ค่าของ IN คือความง่ายในการใช้งาน (การประหยัดในการพิมพ์ชื่อคอลัมน์แต่ละครั้งหลายครั้งและทำให้ใช้งานได้ง่ายขึ้นด้วยตรรกะที่มีอยู่ - คุณไม่ต้องกังวลเกี่ยวกับและ / หรือลำดับความสำคัญเนื่องจาก IN เป็นคำสั่งเดียวด้วยคำสั่ง OR จำนวนมากคุณมี เพื่อให้แน่ใจว่าคุณล้อมรอบด้วยวงเล็บเพื่อให้แน่ใจว่าพวกเขาได้รับการประเมินว่าเป็นเงื่อนไขเดียว)

คำตอบเดียวที่แท้จริงให้กับคำถามของคุณPROFILE คำสั่งของคุณ แล้วคุณจะรู้ว่าอะไรดีที่สุดในสถานการณ์เฉพาะของคุณ


ในทางสถิติระหว่างมีโอกาสที่จะเรียกดัชนีช่วง IN () ไม่มีสิทธิ์นี้ แต่ใช่ชายหาดถูกต้อง: คุณต้องโปรไฟล์คำขอของคุณเพื่อทราบว่ามีการใช้ดัชนีหรือไม่และดัชนีใด เป็นการยากที่จะคาดเดาว่าเครื่องมือเพิ่มประสิทธิภาพ MySQL จะเลือกอะไร
Savageman

"ฉันเข้าใจว่า IN จะถูกแปลงเป็นงบ OR จำนวนมาก" คุณอ่านนี่มาจากไหน ฉันคาดหวังว่ามันจะใส่ไว้ใน hashmap เพื่อทำการค้นหา O (1)
Ztyx

IN ของการถูกแปลงเป็น OR เป็นวิธีที่ SQLServer จัดการมัน (หรืออย่างน้อยก็ทำ - อาจมีการเปลี่ยนแปลงในตอนนี้ไม่ได้ใช้ในปี) ฉันไม่สามารถหาหลักฐานใด ๆ ที่ MySQL ทำ
RichardAtHome

4
คำตอบนี้ถูกต้องระหว่างถูกแปลงเป็น "1 <= film_id <= 5" อีกสองโซลูชั่นจะไม่พับลงในช่วงเดียว ฉันมีโพสต์บล็อกที่แสดงสิ่งนี้โดยใช้การติดตาม OPTIMIZER ที่นี่: tocker.ca/2015/05/25/ …
Morgan Tocker

13

ขึ้นอยู่กับสิ่งที่คุณกำลังทำ ช่วงกว้างเท่าไหร่ประเภทข้อมูลคืออะไร (ฉันรู้ว่าตัวอย่างของคุณใช้ชนิดข้อมูลตัวเลข แต่คำถามของคุณยังสามารถนำไปใช้กับประเภทข้อมูลที่แตกต่างกันได้มากมาย)

นี่คืออินสแตนซ์ที่คุณต้องการเขียนแบบสอบถามทั้งสองวิธี ทำให้มันใช้งานได้แล้วใช้อธิบายเพื่อหาความแตกต่างของการดำเนินการ

ฉันแน่ใจว่ามีคำตอบที่เป็นรูปธรรมสำหรับเรื่องนี้ แต่นี่คือวิธีที่ฉันจะพูดจริงหาคำตอบสำหรับคำถามที่ฉันได้รับ

นี่อาจเป็นความช่วยเหลือบางอย่าง: http://forge.mysql.com/wiki/Top10SQLPerformanceTips

ขอแสดงความนับถือ
แฟรงค์


2
นี่ควรเป็นคำตอบที่เลือก
Jon z

3
ลิงค์เก่า - ฉันคิดว่านี่อาจจะเทียบเท่าหรือไม่ wikis.oracle.com/pages/viewpage.action?pageId=27263381 (ขอบคุณ Oracle ;-P)
ilasno

1
ในหน้าเทียบเท่ามันบอกว่า: "หลีกเลี่ยงการใช้ IN (... ) เมื่อเลือกในเขตข้อมูลที่จัดทำดัชนีมันจะฆ่าประสิทธิภาพของแบบสอบถามแบบใช้คำสั่ง" - ความคิดใด ๆ ที่เป็นสาเหตุ?
jorisw

URL หมดอายุแล้ว
Steve Jiang

7

ฉันคิดว่าคำอธิบายหนึ่งสำหรับผู้สังเกตการณ์ของซันไชน์คือ MySQL จริง ๆ แล้วเรียงลำดับค่าในคำสั่ง IN หากเป็นค่าคงที่ทั้งหมดและใช้การค้นหาแบบไบนารีซึ่งมีประสิทธิภาพมากกว่าแบบธรรมดาหรือทางเลือก ฉันจำไม่ได้ว่าฉันอ่านตรงไหน แต่ผลลัพธ์ของผู้ที่มองดูแล้วเป็นข้อพิสูจน์


4

เมื่อคุณคิดว่ามันปลอดภัย ...

คุณค่าของคุณคืออะไรeq_range_index_dive_limit? คุณมีรายการในINประโยคมากขึ้นหรือน้อยลงหรือไม่?

สิ่งนี้จะไม่รวมเกณฑ์มาตรฐาน แต่จะมองเข้าไปในผลงานภายในเล็กน้อย ลองใช้เครื่องมือเพื่อดูว่าเกิดอะไรขึ้น - เครื่องมือเพิ่มประสิทธิภาพการติดตาม

แบบสอบถาม: SELECT * FROM canada WHERE id ...

ด้วยORค่า 3 ค่าส่วนหนึ่งของการติดตามจะเป็นดังนี้:

       "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 ORsจะถูกให้ นี้ก็หมายความว่าORจะไม่กลายเป็นINและ InnoDB จะดำเนินการพวงของ=การทดสอบผ่าน ICP (ฉันไม่รู้สึกว่ามันคุ้มค่าที่จะพิจารณา MyISAM)

(นี่คือ Percona 5.6.22-71.0-log; idเป็นดัชนีรอง)

ตอนนี้สำหรับ IN () โดยมีค่าน้อย

eq_range_index_dive_limit= 10; มี 8 ค่า

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

โปรดทราบว่าไม่ได้ดูเหมือนจะกลายเป็นINOR

สังเกตด้าน: ขอให้สังเกตว่าค่าคงที่ถูกจัดเรียง สิ่งนี้มีประโยชน์ในสองวิธี:

  • การกระโดดไปรอบ ๆ ให้น้อยลงอาจมีการแคชที่ดีกว่า I / O ที่น้อยลงเพื่อรับค่าทั้งหมด
  • หากแบบสอบถามที่คล้ายกันสองรายการมาจากการเชื่อมต่อแยกต่างหากและอยู่ในธุรกรรมมีโอกาสที่ดีกว่าที่จะได้รับการล่าช้าแทนการหยุดชะงักเนื่องจากรายการที่ทับซ้อนกัน

ในที่สุด, 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"
          }
        ]

หมายเหตุด้านข้าง: ฉันต้องการสิ่งนี้เนื่องจากความเป็นจำนวนมากของร่องรอย:

@@global.optimizer_trace_max_mem_size = 32222;

3

หรือจะช้าที่สุด ไม่ว่าจะเป็น IN หรือ BETWEEN จะเร็วกว่านั้นขึ้นอยู่กับข้อมูลของคุณ แต่ฉันคาดว่า BETWEEN นั้นจะเร็วกว่าปกติเพราะมันสามารถใช้ช่วงจากดัชนีได้อย่างง่ายดาย


3

ด้านล่างนี้เป็นรายละเอียดของ 6 คำสั่งโดยใช้ MySQL 5.6 @SQLFiddle

โดยสรุปแบบสอบถาม 6 รายการครอบคลุมคอลัมน์ที่จัดทำดัชนีอย่างอิสระและมีการใช้แบบสอบถาม 2 รายการต่อชนิดข้อมูล แบบสอบถามทั้งหมดส่งผลให้ใช้ดัชนีโดยไม่คำนึงถึง IN () หรือ OR ที่ใช้งาน

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

ฉันแค่อยากจะ debunk งบทำให้ OR หมายถึงไม่สามารถใช้ดัชนีได้ สิ่งนี้ไม่เป็นความจริง ดัชนีสามารถใช้ในแบบสอบถามโดยใช้ OR เป็น 6 แบบสอบถามในตัวอย่างต่อไปนี้แสดง

สำหรับฉันแล้วดูเหมือนว่าหลายคนไม่สนใจความจริงที่ว่า IN () เป็นทางลัดไวยากรณ์สำหรับชุดของ OR ที่ความแตกต่างในระดับ perfomance ขนาดเล็กระหว่างการใช้ IN () -v- OR นั้นมีความสำคัญน้อยมาก

ในขณะที่ขนาดใหญ่กว่าใน () สะดวกกว่าแน่นอน แต่มันหมายถึงชุดของเงื่อนไขหรือมีเหตุผล สถานการณ์เปลี่ยนไปสำหรับแต่ละแบบสอบถามดังนั้นการทดสอบคิวรีของคุณบนตารางจะดีที่สุดเสมอ

สรุปแผน 6 ข้ออธิบายทั้งหมด "การใช้เงื่อนไขดัชนี" (เลื่อนไปทางขวา)

  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  

ซอ Fiddle

การติดตั้ง MySQL 5.6 Schema :

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
;

แบบสอบถาม 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

ผลลัพธ์ :

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

แบบสอบถาม 2 :

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

ผลลัพธ์ :

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

แบบสอบถาม 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')

ผลลัพธ์ :

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

แบบสอบถาม 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')
        )

ผลลัพธ์ :

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

แบบสอบถาม 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'

ผลลัพธ์ :

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

แบบสอบถาม 6 :

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

ผลลัพธ์ :

|          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

ฉันจะเดิมพันพวกเขาเหมือนกันคุณสามารถทดสอบโดยทำดังต่อไปนี้:

วนรอบ "ใน (1,2,3,4)" 500 ครั้งและดูว่าต้องใช้เวลานานเท่าใด วนรอบ "= 1 หรือ = 2 หรือ = 3 ... " เวอร์ชัน 500 ครั้งและดูว่ามันใช้งานได้นานแค่ไหน

คุณสามารถลองเข้าร่วมได้หากบางฟิลด์เป็นดัชนีและตารางของคุณใหญ่มากอาจเร็วกว่า ...

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

ฉันลองวิธีการเข้าร่วมด้านบนบน SQL Server ของฉันและมันก็เกือบจะเหมือนกับใน (1,2,3,4) และพวกเขาทั้งคู่ส่งผลให้ค้นหาดัชนีคลัสเตอร์ ฉันไม่แน่ใจว่า MySQL จะจัดการกับพวกเขาอย่างไร


2

2018 : IN (... )เร็วขึ้น แต่> = && <=เป็นได้เร็วขึ้นกว่าใน

นี่คือฉันมาตรฐาน


0

จากสิ่งที่ฉันเข้าใจเกี่ยวกับวิธีการที่คอมไพเลอร์ปรับการค้นหาประเภทเหล่านี้ให้เหมาะสมการใช้ส่วนคำสั่ง IN จะมีประสิทธิภาพมากกว่าข้อ OR หลายข้อ หากคุณมีค่าที่สามารถใช้อนุประโยค BETWEEN ได้จะยิ่งมีประสิทธิภาพมากขึ้น


0

ฉันรู้ว่าตราบใดที่คุณมีดัชนีในฟิลด์ BETWEEN จะใช้มันเพื่อค้นหาปลายด้านหนึ่งอย่างรวดเร็วจากนั้นข้ามไปที่อื่น สิ่งนี้มีประสิทธิภาพมากที่สุด

อธิบายทุกครั้งที่ฉันเห็นรายการ "IN (... )" และ "... หรือ ... " ให้ใช้แทนกันได้และมีประสิทธิภาพเท่ากัน (ใน) สิ่งที่คุณคาดหวังเนื่องจากเครื่องมือเพิ่มประสิทธิภาพไม่มีวิธีที่จะทราบว่าประกอบด้วยช่วงเวลาหรือไม่ นอกจากนี้ยังเทียบเท่ากับ UNION ALL SELECT ในแต่ละค่า


0

ตามที่อธิบายโดยคนอื่น ๆ IN นั้นถูกเลือกดีกว่าหรือเกี่ยวกับประสิทธิภาพของคิวรี

ข้อความค้นหาที่มีเงื่อนไข OR อาจใช้เวลาดำเนินการนานกว่าในกรณีด้านล่าง

  1. เพื่อดำเนินการถ้าตัวเพิ่มประสิทธิภาพ MySQL เลือกดัชนีอื่นใดให้มีประสิทธิภาพ (ในระหว่างกรณีบวกปลอม)
  2. ถ้าจำนวนบันทึกมากกว่า (ตามที่ระบุไว้อย่างชัดเจนโดย Jacob)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.