Hiệu suất MYSQL HOẶC so với IN


180

Tôi tự hỏi nếu có bất kỳ sự khác biệt liên quan đến hiệu suất giữa các sau đây

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

hoặc MySQL sẽ tối ưu hóa SQL theo cùng một cách trình biên dịch sẽ tối ưu hóa mã?

EDIT: Thay đổi AND's thành OR' vì lý do được nêu trong các bình luận.


Tôi cũng đang nghiên cứu điều này, nhưng đối lập với một số tuyên bố rằng IN sẽ được chuyển đổi thành hàng OR s I could say that it can also be converted to UNIONđược đề xuất thay thế OR `để tối ưu hóa truy vấn.
Jāni Gruzis

Câu trả lời:


249

Tôi cần phải biết điều này chắc chắn, vì vậy tôi đã điểm chuẩn cả hai phương pháp. Tôi luôn luôn thấy INnhanh hơn nhiều so với việc sử dụng OR.

Đừng tin những người đưa ra "ý kiến" của họ, khoa học là tất cả về thử nghiệm và bằng chứng.

Tôi đã chạy một vòng 1000 lần các truy vấn tương đương (để thống nhất, tôi đã sử dụng sql_no_cache):

IN: 2.34969592094s

OR: 5,83781504631s

Cập nhật:
(Tôi không có mã nguồn cho thử nghiệm ban đầu, như cách đây 6 năm, mặc dù nó trả về kết quả trong cùng phạm vi với thử nghiệm này)

Trong yêu cầu một số mã mẫu để kiểm tra điều này, đây là trường hợp sử dụng đơn giản nhất có thể. Sử dụng Eloquent để đơn giản hóa cú pháp, tương đương SQL thô thực hiện như nhau.

$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
Những chỉ số đã được sử dụng trong các thử nghiệm này?
eggyal

5
Tôi cũng đã tối ưu hóa các truy vấn và phát hiện ra rằng INcâu lệnh nhanh hơn khoảng 30% so với câu hỏi OR.
Timo002

12
Do not believe people who give their "opinion"Bạn đúng 100%, không may Stack Overflow đầy ắp chúng
elipoultorak

7
Lý do hiệu suất (trích dẫn tài liệu MariaDB (một nhánh miễn phí mới của MySQL)): => nếu cột của bạn là số nguyên, hãy chuyển số nguyên cho quá ...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
Như một hệ quả tất yếu để ' Đừng tin những người đưa ra "ý kiến" của họ: Cung cấp số liệu hiệu suất mà không bao gồm các tập lệnh, bảng và chỉ mục được sử dụng để có được các số liệu đó khiến chúng không thể kiểm chứng được. Như vậy, các số liệu cũng tốt như một "ý kiến".
vỡ mộng

67

Tôi cũng đã làm một bài kiểm tra cho nhân viên Google trong tương lai. Tổng số kết quả trả về là 7264 trên 10000

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

Truy vấn này mất 0.1239vài giây

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

Truy vấn này mất 0.0433vài giây

IN nhanh gấp 3 lần OR


15
Công cụ MySQL nào là nó và bạn đã xóa bộ đệm MySQL và bộ đệm tệp OS ở giữa hai truy vấn?
dabest1

2
Bài kiểm tra của bạn là một trường hợp sử dụng hẹp. Truy vấn trả về 72% dữ liệu và không có khả năng hưởng lợi từ các chỉ mục.
vỡ mộng

Tôi cá là phần lớn thời gian đó là tiêu tốn truy vấn, phân tích cú pháp và lập kế hoạch truy vấn. Đó chắc chắn là một điều cần cân nhắc: nếu bạn sắp có 10k câu lệnh HOẶC, bạn sẽ có rất nhiều văn bản dư thừa chỉ cần diễn đạt bằng OR: tốt nhất nên sử dụng biểu thức nhỏ gọn nhất có thể.
giám mục

17

Câu trả lời được chấp nhận không giải thích lý do.

Dưới đây được trích dẫn từ MySQL hiệu suất cao, phiên bản thứ 3.

Trong nhiều máy chủ cơ sở dữ liệu, IN () chỉ là một từ đồng nghĩa cho nhiều mệnh đề OR, vì hai mệnh đề này tương đương nhau về mặt logic. Không phải như vậy trong MySQL, sắp xếp các giá trị trong danh sách IN () và sử dụng tìm kiếm nhị phân nhanh để xem liệu một giá trị có trong danh sách hay không. Đây là O (Log n) về kích thước của danh sách, trong khi một chuỗi mệnh đề OR tương đương là O (n) trong kích thước của danh sách (nghĩa là chậm hơn nhiều đối với danh sách lớn)


Tham khảo tuyệt vời cho lý do cơ sở dữ liệu cụ thể. Đẹp!
Joshua Pinter

Hoàn hảo và chính xác
gaurav9620

16

Tôi nghĩ rằng GIỮA sẽ nhanh hơn vì nó nên được chuyển đổi thành:

Field >= 0 AND Field <= 5

Theo hiểu biết của tôi, IN sẽ được chuyển đổi thành một loạt các câu lệnh OR. Giá trị của IN là dễ sử dụng. (Tiết kiệm khi phải nhập từng tên cột nhiều lần và cũng giúp sử dụng dễ dàng hơn với logic hiện có - bạn không phải lo lắng về ưu tiên AND / OR vì IN là một câu lệnh. Với một loạt các câu lệnh OR, bạn có để đảm bảo bạn bao quanh chúng bằng dấu ngoặc đơn để đảm bảo chúng được đánh giá là một điều kiện.)

Câu trả lời thực sự duy nhất cho câu hỏi của bạn là HỒ SƠ SỐ LƯỢNG CỦA BẠN . Sau đó, bạn sẽ biết những gì làm việc tốt nhất trong tình huống cụ thể của bạn.


Theo thống kê, Giữa có cơ hội kích hoạt chỉ số phạm vi. IN () không có đặc quyền này. Nhưng vâng, bãi biển là đúng: bạn CẦN lập hồ sơ yêu cầu của bạn để biết liệu một chỉ mục được sử dụng và chỉ số nào. Thật khó để dự đoán những gì trình tối ưu hóa MySQL sẽ chọn.
Savageman

"Theo hiểu biết của tôi rằng IN sẽ được chuyển đổi thành một loạt các câu lệnh OR." Bạn đã đọc nó ở đâu? Tôi hy vọng nó sẽ đưa nó vào một hashmap để thực hiện tra cứu O (1).
Ztyx

IN đang được chuyển đổi thành OR là cách SQLServer xử lý nó (hoặc ít nhất là nó đã làm - có thể đã thay đổi ngay bây giờ, đã không sử dụng nó trong nhiều năm). Tôi đã không thể tìm thấy bất kỳ bằng chứng nào cho thấy MySQL làm điều này.
RichardAtHome

4
Câu trả lời này là chính xác, giữa được chuyển đổi thành "1 <= film_id <= 5". Hai giải pháp khác không được xếp vào một điều kiện phạm vi duy nhất. Tôi có một bài đăng trên blog chứng minh điều này bằng cách sử dụng OPTIMIZER TRACE tại đây: tocker.ca/2015/05/25/ mẹo
Morgan Tocker

13

Nó phụ thuộc vào những gì bạn đang làm; phạm vi rộng bao nhiêu, loại dữ liệu là gì (tôi biết ví dụ của bạn sử dụng loại dữ liệu số nhưng câu hỏi của bạn cũng có thể áp dụng cho rất nhiều loại dữ liệu khác nhau).

Đây là một ví dụ nơi bạn muốn viết truy vấn theo cả hai cách; làm cho nó hoạt động và sau đó sử dụng GIẢI THÍCH để tìm ra sự khác biệt thực hiện.

Tôi chắc chắn có một câu trả lời cụ thể cho vấn đề này nhưng đây là cách tôi sẽ, thực tế nói, tìm ra câu trả lời cho câu hỏi của tôi.

Đây có thể là một số trợ giúp: http://forge.mysql.com/wiki/Top10QueryPerformanceTips

Trân trọng,
Frank


2
Đây phải là câu trả lời được lựa chọn.
Jon z

3
Liên kết đã cũ - tôi nghĩ rằng điều này có thể là tương đương? wikis.oracle.com/pages/viewpage.action?pageId=27263381 (cảm ơn Oracle ;-P)
ilasno

1
Trên trang tương đương, nó ghi: "Tránh sử dụng IN (...) khi chọn trên các trường được lập chỉ mục, Nó sẽ giết hiệu suất của truy vấn CHỌN." - Có biết tại sao không?
jorisw

url đã hết hạn
Steve Jiang

7

Tôi nghĩ một lời giải thích cho sự quan sát của sunseeker là MySQL thực sự sắp xếp các giá trị trong câu lệnh IN nếu chúng đều là các giá trị tĩnh và sử dụng tìm kiếm nhị phân, hiệu quả hơn so với phương án OR đơn giản. Tôi không thể nhớ mình đã đọc nó ở đâu, nhưng kết quả của sunseek dường như là một bằng chứng.


4

Chỉ khi bạn nghĩ rằng nó an toàn ...

Giá trị của bạn là eq_range_index_dive_limitgì? Cụ thể, bạn có nhiều hay ít vật phẩm trongIN mệnh đề không?

Điều này sẽ không bao gồm Điểm chuẩn, nhưng sẽ nhìn vào hoạt động bên trong một chút. Chúng ta hãy sử dụng một công cụ để xem những gì đang diễn ra - Trình tối ưu hóa.

Truy vấn: SELECT * FROM canada WHERE id ...

Với một ORtrong 3 giá trị , một phần của dấu vết trông giống như:

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

Lưu ý cách ICP đang được đưa ra ORs. Đây ngụ ý rằng ORkhông được biến thành IN, và InnoDB sẽ được thực hiện một loạt các= kiểm tra thông qua ICP. (Tôi không cảm thấy đáng để xem xét MyISAM.)

(Đây là nhật ký 5.6,22-71,0 của Percona; idlà chỉ số phụ.)

Bây giờ cho IN () với một vài giá trị

eq_range_index_dive_limit= 10; Có 8 giá trị.

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

Lưu ý rằng INdường như không được chuyển thànhOR .

Một lưu ý phụ: Lưu ý rằng các giá trị không đổi đã được sắp xếp . Điều này có thể có lợi theo hai cách:

  • Bằng cách nhảy xung quanh ít hơn, có thể có bộ nhớ đệm tốt hơn, ít I / O hơn để có được tất cả các giá trị.
  • Nếu hai truy vấn tương tự đến từ các kết nối riêng biệt và chúng nằm trong các giao dịch, có nhiều khả năng nhận được sự chậm trễ thay vì bế tắc do danh sách chồng chéo.

Cuối cùng, IN () với rất nhiều giá trị

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

Lưu ý bên lề: Tôi cần điều này do sự đa dạng của dấu vết:

@@global.optimizer_trace_max_mem_size = 32222;

3

HOẶC sẽ chậm nhất. Việc IN hay GIỮA nhanh hơn sẽ phụ thuộc vào dữ liệu của bạn, nhưng tôi hy vọng GIỮA sẽ nhanh hơn bình thường vì đơn giản là có thể lấy một phạm vi từ một chỉ mục (giả sử một sốField được lập chỉ mục).


3

Dưới đây là chi tiết về 6 truy vấn bằng MySQL 5.6 @QueryFiddle

Tóm lại, 6 truy vấn bao gồm các cột được lập chỉ mục độc lập và 2 truy vấn được sử dụng cho mỗi loại dữ liệu. Tất cả các truy vấn dẫn đến việc sử dụng một chỉ mục bất kể IN () hoặc OR đang được sử dụng.

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

Tôi thực sự chỉ muốn gỡ lỗi các câu lệnh được thực hiện mà OR có nghĩa là không có chỉ mục nào có thể được sử dụng. Điều này không đúng. Các chỉ mục có thể được sử dụng trong các truy vấn sử dụng OR làm 6 truy vấn trong các ví dụ sau hiển thị.

Ngoài ra, dường như nhiều người đã bỏ qua thực tế rằng IN () là một phím tắt cú pháp cho một tập hợp OR. Ở quy mô nhỏ, sự khác biệt giữa việc sử dụng IN () -v- HOẶC cực kỳ (vô hạn).

Mặc dù ở quy mô lớn hơn IN () chắc chắn thuận tiện hơn, nhưng nó tương đương với một tập hợp các điều kiện OR. Thay đổi hoàn cảnh cho mỗi truy vấn để kiểm tra truy vấn của bạn trên các bảng của bạn luôn là tốt nhất.

Tóm tắt 6 kế hoạch giải thích, tất cả "Sử dụng điều kiện chỉ mục" (cuộn sang phải)

  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  

Câu đố SQL

Thiết lập lược đồ 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
;

Truy vấn 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

Kết quả :

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

Truy vấn 2 :

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

Kết quả :

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

Truy vấn 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')

Kết quả :

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

Truy vấn 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')
        )

Kết quả :

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

Truy vấn 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'

Kết quả :

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

Truy vấn 6 :

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

Kết quả :

|          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

Tôi cá là chúng giống nhau, bạn có thể chạy thử bằng cách làm như sau:

lặp lại "trong (1,2,3,4)" 500 lần và xem mất bao lâu. lặp qua phiên bản "= 1 hoặc = 2 hoặc = 3 ..." 500 lần và xem thời gian chạy.

bạn cũng có thể thử một cách tham gia, nếu someField là một chỉ mục và bảng của bạn lớn thì có thể nhanh hơn ...

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

Tôi đã thử phương thức nối ở trên trên Máy chủ SQL của tôi và nó gần giống như trong (1,2,3,4) và cả hai đều dẫn đến một tìm kiếm chỉ mục được nhóm. Tôi không chắc chắn cách MySQL sẽ xử lý chúng.



0

Từ những gì tôi hiểu về cách trình biên dịch tối ưu hóa các loại truy vấn này, sử dụng mệnh đề IN hiệu quả hơn nhiều mệnh đề OR. Nếu bạn có các giá trị trong đó mệnh đề BETweEN có thể được sử dụng, điều đó vẫn hiệu quả hơn.


0

Tôi biết rằng, miễn là bạn có một chỉ mục trên Trường, GIỮA sẽ sử dụng nó để nhanh chóng tìm thấy một đầu, sau đó đi qua đầu kia. Đây là hiệu quả nhất.

Mỗi GIẢI THÍCH mà tôi thấy cho thấy "IN (...)" và "... HOẶC ..." có thể hoán đổi cho nhau và hiệu quả như nhau (trong). Mà bạn mong đợi, vì trình tối ưu hóa không có cách nào để biết liệu chúng có bao gồm một khoảng hay không. Nó cũng tương đương với UNION ALL CHỌN trên các giá trị riêng lẻ.


0

Như được giải thích bởi những người khác, IN được chọn tốt hơn OR so với hiệu suất truy vấn.

Các truy vấn với điều kiện OR có thể mất nhiều thời gian thực hiện hơn trong các trường hợp dưới đây.

  1. để thực thi nếu trình tối ưu hóa MySQL chọn bất kỳ chỉ mục nào khác có hiệu quả (trong trường hợp dương tính giả).
  2. Nếu số lượng hồ sơ nhiều hơn (Như Jacob đã nêu rõ)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.