MYSQL OR против 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 так же, как компиляторы оптимизируют код?

РЕДАКТИРОВАТЬ: Изменил ANDOR' по причине, указанной в комментариях.


Я также исследую эту вещь, но в противоположность некоторым утверждениям, что IN будет преобразован в строку OR, s I could say that it can also be converted to UNIONкоторая рекомендуется для замены OR для оптимизации запроса.
Янис Грузис

Ответы:


249

Мне нужно было знать это наверняка, поэтому я сравнил оба метода. Я последовательно обнаружил, INчто гораздо быстрее, чем с помощью OR.

Не верьте людям, которые высказывают свое «мнение», наука - это все о проверках и доказательствах.

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

IN: 2.34969592094s

OR: 5.83781504631s

Обновление:
(У меня нет исходного кода для исходного теста, как это было 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% правы, к сожалению, переполнение стека их
полно

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, у вас будет много избыточного текста, просто выражающего его OR: лучше всего использовать наиболее компактное из возможных выражений.
епископ

18

Принятый ответ не объясняет причину.

Ниже приведены цитаты из High Performance MySQL, 3-е издание.

На многих серверах баз данных IN () является просто синонимом для нескольких предложений OR, потому что оба логически эквивалентны. Не так в MySQL, который сортирует значения в списке IN () и использует быстрый двоичный поиск, чтобы увидеть, есть ли значение в списке. Это O (Log n) по размеру списка, тогда как эквивалентная серия предложений OR равна O (n) по размеру списка (т. Е. Намного медленнее для больших списков)


Фантастическая ссылка на конкретную причину базы данных. Ницца!
Джошуа Пинтер

Идеально и
точно

16

Я думаю, что МЕЖДУ будет быстрее, так как он должен быть преобразован в:

Field >= 0 AND Field <= 5

Насколько я понимаю, IN все равно будет преобразован в кучу операторов OR. Значение IN - это простота использования. (Экономия на необходимости вводить имя каждого столбца несколько раз, а также упрощает использование с существующей логикой - вам не нужно беспокоиться о приоритете AND / OR, потому что IN - это один оператор. С кучей операторов OR вы получаете чтобы вы заключили их в круглые скобки, чтобы они были оценены как одно условие.)

Единственный реальный ответ на ваш вопрос - ПРОФИЛЬ ВАШИХ ЗАПРОСОВ . Тогда вы будете знать, что работает лучше всего в вашей конкретной ситуации.


По статистике, Between имеет шанс активировать индекс диапазона. IN () не имеет этой привилегии. Но да, пляж прав: вам НУЖНО профилировать ваш запрос, чтобы узнать, используется ли индекс и какой. Очень сложно предсказать, что выберет оптимизатор MySQL.
Savageman

«Насколько я понимаю, IN в любом случае преобразуется в набор операторов OR». Где ты это прочитал? Я ожидаю, что он поместит его в хэш-карту для поиска O (1).
Ztyx

Преобразование IN в OR - это то, как SQLServer обрабатывает его (или, по крайней мере, он это сделал - возможно, изменился бы сейчас, не использовал его годами). Я не смог найти никаких доказательств того, что MySQL делает это.
RichardAtHome

4
Этот ответ правильный, между преобразуется в «1 <= film_id <= 5». Два других решения не объединены в одно условие диапазона. У меня есть запись в блоге, которая демонстрирует это с помощью OPTIMIZER TRACE здесь: tocker.ca/2015/05/25/…
Морган Токер

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». - Есть идеи, почему это так?
Джорисв

срок действия
Стив Цзян

7

Я думаю, что одним из объяснений наблюдения Sunseeker является то, что MySQL фактически сортирует значения в операторе IN, если они все являются статическими значениями и используют бинарный поиск, который более эффективен, чем простая альтернатива ИЛИ. Я не могу вспомнить, где я это читал, но результат Sunseeker кажется доказательством.


4

Как раз тогда, когда вы думали, что это безопасно ...

Какова ваша ценность eq_range_index_dive_limit? В частности, у вас есть больше или меньше пунктов в INпредложении?

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

Запрос: SELECT * FROM canada WHERE id ...

С OR3 значениями часть трассировки выглядит так:

       "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; 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 быстрее, будет зависеть от ваших данных, но я ожидаю, что BETWEEN будет быстрее, как обычно, поскольку он может просто взять диапазон из индекса (при условии, что someField проиндексирован).


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 () является синтаксическим ярлыком для набора OR. В небольших масштабах различия в производительности между использованием IN () -v- ИЛИ чрезвычайно (бесконечно) незначительны.

Хотя в большем масштабе IN (), безусловно, удобнее, но все равно логически соответствует ряду условий 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  

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

Могу поспорить, что они одинаковые, вы можете запустить тест, выполнив следующие действия:

переверните "in (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 более эффективно, чем использование нескольких предложений OR. Если у вас есть значения, в которых можно использовать предложение BETWEEN, это еще более эффективно.


0

Я знаю, что до тех пор, пока у вас есть индекс по полю, МЕЖДУ будет использовать его, чтобы быстро найти один конец, а затем перейти к другому. Это наиболее эффективно.

Каждое ОБЪЯСНЕНИЕ, которое я видел, показывает, что «IN (...)» и «... ИЛИ ...» взаимозаменяемы и одинаково (не) эффективны. Как и следовало ожидать, так как оптимизатор не может знать, содержат ли они интервал или нет. Это также эквивалентно UNION ALL SELECT для отдельных значений.


0

Как объяснили другие, IN лучше выбирается, чем OR в отношении производительности запросов.

Запросы с условием ИЛИ могут занять больше времени в следующих случаях.

  1. выполнить, если оптимизатор MySQL выбирает любой другой индекс, чтобы быть эффективным (во время ложных положительных случаев).
  2. Если количество записей больше (как ясно сказано Джейкобом)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.