Продуктивність MYSQL АБО та ІН


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's OR' з причини, зазначеної в коментарях.


Я також досліджую цю річ, але всупереч деяким твердженням, що IN буде перетворений на рядок АБО s I could say that it can also be converted to UNION, який рекомендується замінити АБО для оптимізації запиту.
Jānis Gruzis

Відповіді:


249

Мені це потрібно було знати точно, тому я орієнтував обидва методи. Я послідовно виявив, INщо це набагато швидше, ніж використання OR.

Не вірте людям, які дають свою "думку", наука - це все про тестування та докази.

Я запустив цикл 1000x еквівалентних запитів (для послідовності я використав sql_no_cache):

IN: 2.34969592094с

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% швидше, ніж an OR.
Timo002

12
Do not believe people who give their "opinion"Ви на 100% праві, переповнення стека, на жаль, повне ними
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

Я також зробив тест для майбутніх Googlers. Загальна кількість повернених результатів - 7264 з 10000

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: найкраще використовувати максимально компактний вираз.
єпископ

17

Прийнята відповідь не пояснює причину.

Нижче наводимо цитату з високопродуктивного MySQL, 3-е видання.

На багатьох серверах баз даних IN () є лише синонімом декількох пропозицій АБО, оскільки ці два логічно рівнозначні. Не так у MySQL, який сортує значення у списку IN () та використовує швидкий двійковий пошук, щоб побачити, чи є у списку значення. Це O (Log n) за розміром списку, тоді як еквівалентна серія пропозицій OR або O (n) є розміром списку (тобто набагато повільніше для великих списків)


Фантастичне посилання на конкретну причину бази даних. Приємно!
Джошуа Пінтер

Ідеально і до речі
gaurav9620

16

Я думаю, що МЕЖЕ буде швидше, оскільки його слід перетворити на:

Field >= 0 AND Field <= 5

Наскільки я розумію, що IN все одно перетвориться на купу операторів АБО. Значення IN - це простота використання. (Заощаджуючи необхідність вводити кожне ім’я кожного стовпця кілька разів, а також полегшує його використання з існуючою логікою - вам не доведеться турбуватися про пріоритет І / АБО, оскільки IN - це один вислів. З купою операторів АБО у вас є щоб ви оточили їх круглими дужками, щоб переконатися, що вони оцінені як одна умова.)

Єдина реальна відповідь на ваше запитання - ПРОФІЛЮЙТЕ СВОЇ ЗАПИТАННЯ . Тоді ви дізнаєтесь, що найкраще працює у вашій конкретній ситуації.


Статистично, "Між" є шанс запустити індекс діапазону. IN () не має цієї привілеї. Але так, пляж - це правильно: НЕОБХІДНО профайлювати запит, щоб дізнатися, чи використовується індекс, а який - Справді важко передбачити, який оптимізатор MySQL обере.
Савагеман

"Я розумію, що IN все одно буде перетворений на купу операторів АБО." Де ти це прочитав? Я б очікував, що він помістить його в хешмап, щоб зробити O (1) пошуку.
Ztyx

Перетворення IN в ОР - це те, як SQLServer обробляє це (або, принаймні, це зробило - можливо, змінилося зараз, не використовував його роками). Мені не вдалося знайти жодних доказів того, що MySQL це робить.
RichardAtHome

4
Ця відповідь правильна, між перетворюється в "1 <= film_id <= 5". Інші два рішення не складені в умовах єдиного діапазону. У мене є повідомлення в блозі, який демонструє це за допомогою ОПТИМІЗАТОРНОЇ ТРЕЙДИ
Morgan Tocker

13

Це залежить від того, що ти робиш; наскільки широкий діапазон, який тип даних (я знаю, що ваш приклад використовує числовий тип даних, але ваше запитання також може стосуватися багатьох різних типів даних).

Це екземпляр, коли ви хочете написати запит обома способами; опрацюйте його, а потім використовуйте EXPLAIN, щоб визначити відмінності у виконанні.

Я впевнений, що на це є конкретна відповідь, але саме так, я б практично зрозумів відповідь на своє запитання.

Це може допомогти: http://forge.mysql.com/wiki/Top10SQLPerformanceTips

З повагою,
Френк


2
Це має бути обрана відповідь.
Jon z

3
Посилання несвіжа - я думаю, це може бути рівнозначно? wikis.oracle.com/pages/viewpage.action?pageId=27263381 (спасибі Oracle ;-P)
ilasno

1
На еквівалентній сторінці написано: "Уникайте використання IN (...) при виборі на індексованих полях, це знищить продуктивність SELECT запиту". - Будь-яка ідея, чому це?
jorisw

термін дії минув
Стів Цзян

7

Я думаю, що одне пояснення спостереження sunseeker полягає в тому, що MySQL насправді сортує значення в операторі IN, якщо вони є всіма статичними значеннями та використовують двійковий пошук, який є більш ефективним, ніж звичайна АБО альтернатива. Я не можу згадати, де я це читав, але результат sunseeker, здається, є доказом.


4

Тільки коли ти думав, що це безпечно ...

Яка ваша цінність eq_range_index_dive_limit? Зокрема, у вас є більше або менше пунктів у INпункті?

Це не буде включати тест, але трохи загляне у внутрішню роботу. Давайте скористаємося інструментом, щоб побачити, що відбувається - Optimizer Trace.

Запит: SELECT * FROM canada WHERE id ...

З ORтрьома значеннями частина сліду виглядає так:

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

(Це 5.6.22-71.0-журнал Percona; 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"
          }
        ]

Зауважте, що IN, здається, це не перетворюється OR.

Побічна примітка: Зауважте, що постійні значення були відсортовані . Це може бути корисно двома способами:

  • Якщо менше стрибати, можливо, буде краще кешування, менше вводу / виводу, щоб дістатись до всіх значень.
  • Якщо два подібних запити надходять із окремих з'єднань, і вони перебувають у транзакціях, є більша ймовірність отримати затримку замість тупикового зв'язку через перекриття списків.

Нарешті, 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 буде швидше нормально, оскільки він може просто взяти діапазон від індексу (якщо припустити, що деяке поле індексується).


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

Я дуже хотів розблокувати заяви, зроблені з приводу того, що АБО означає, що індекс не може бути використаний. Це неправда. Індекси можна використовувати в запитах, що використовують АБО, як 6 запитів на наступних прикладах.

Також мені здається, що багато хто проігнорував той факт, що IN () є ярликом синтаксису для набору АБО. При невеликих масштабах різниця між використанням IN () -v- АБО є надзвичайно (нескінченно) граничними.

Хоча в більших масштабах IN (), звичайно, зручніше, але логічно воно підрівнює набору умов АБО. Зміна обставин для кожного запиту, тому тестування запиту на ваших таблицях завжди найкраще.

Короткий опис 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  

SQL Fiddle

Налаштування схеми 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
;

Запит 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 разів і побачити, як довго вона працює.

Ви також можете спробувати спосіб з'єднання, якщо someField - це індекс, а ваша таблиця велика, це може бути швидше ...

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 впорається з ними.



0

З того, що я розумію про те, як компілятор оптимізує ці типи запитів, використання пункту IN є більш ефективним, ніж декілька пропозицій АБО. Якщо у вас є значення, де може бути використаний пункт BETWEEN, це все-таки є більш ефективним.


0

Я знаю, що, поки у вас є індекс на Field, МЕЖДУ буде використовувати його для швидкого пошуку одного кінця, а потім перехід до іншого. Це найбільш ефективно.

Кожне, що я бачив, показує, що "IN (...)" та "... OR ..." є взаємозамінними та однаково (не) ефективними. Що можна було б очікувати, оскільки оптимізатор не може знати, чи вони містять інтервал чи ні. Це також еквівалент UNION ALL SELECT щодо окремих цінностей.


0

Як пояснюють інші, IN краще вибирати, ніж АБО щодо продуктивності запитів.

Запитання з умовою АБО можуть зайняти більше часу виконання у наведених нижче випадках.

  1. виконати, якщо оптимізатор MySQL обрав будь-який інший індекс для ефективності (під час помилкових позитивних випадків).
  2. Якщо кількість записів більше (Як чітко сказав Яків)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.