IN проти АБО в пункті SQL WHERE


150

Якщо ви маєте справу з великими базами даних, що краще, INабо ORв SQL Where-клаузі?

Чи є різниця в тому, як вони виконуються?


Першим моїм припущенням було б, що АБО працює краще, якщо тільки двигун SQL не перетворить IN в ІЛИ поза сценою. Ви бачили план запитів цих двох?
Радж

Можливий дублікат продуктивності MYSQL OR проти IN
Стів Чемберс

Відповіді:


170

Я припускаю, що ви хочете знати різницю продуктивності між такими:

WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'

Відповідно до посібника для MySQL, якщо значення постійніIN сортує список, а потім використовує двійковий пошук. Я б міг уявити, що ORоцінює їх один за одним у певному порядку. Так INшвидше за деяких обставин.

Найкращий спосіб знати - профайлювати як у своїй базі даних конкретні дані, щоб побачити, що швидше.

Я спробував обидва на MySQL зі 1000000 рядками. Коли стовпчик індексується, різниці в продуктивності не помітна - обидва майже миттєві. Коли стовпець не індексується, я отримав ці результати:

SELECT COUNT(*) FROM t_inner WHERE val IN (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
1 row fetched in 0.0032 (1.2679 seconds)

SELECT COUNT(*) FROM t_inner WHERE val = 1000 OR val = 2000 OR val = 3000 OR val = 4000 OR val = 5000 OR val = 6000 OR val = 7000 OR val = 8000 OR val = 9000;
1 row fetched in 0.0026 (1.7385 seconds)

Тож у цьому випадку метод, що використовує АБО, приблизно на 30% повільніше. Додавання більше термінів робить різницю більшою. Результати можуть залежати від інших баз даних та інших даних.


20
Якщо оптимізатор коштує своєї солі, він повинен виконувати те саме.
Янік Бернет

27
@inflagranti: На жаль, жоден оптимізатор не ідеальний. Оптимізатори - це надзвичайно складні програми, і кожна реалізація матиме свої сильні та слабкі сторони. Ось чому, я кажу, вам слід ознайомитися з конкретною реалізацією. Я б міг уявити, що додаткова структура INметоду полегшує оптимізацію, ніж цілий букет, можливо, супутні ORпропозиції. Я був би здивований, якщо є двигун, де ORметод швидший, але я не здивований, що бувають випадки, коли АБО повільніше.
Марк Байєрс

2
@MarkByers Чи не міг оптимізатор завжди замінити кілька ORs на IN?
tymtam

36

Найкращий спосіб це дізнатися - це переглянути План виконання.


Я спробував це з Oracle , і це було точно так само.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );

Незважаючи на те, що запит використовується IN, План виконання говорить, що він використовує OR:

--------------------------------------------------------------------------------------    
| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |    
--------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT  |                  |     8 |  1416 |   163   (2)| 00:00:02 |    
|*  1 |  TABLE ACCESS FULL| PERFORMANCE_TEST |     8 |  1416 |   163   (2)| 00:00:02 |    
--------------------------------------------------------------------------------------    

Predicate Information (identified by operation id):                                       
---------------------------------------------------                                       

   1 - filter("OBJECT_NAME"='DBMS_LOB' OR "OBJECT_NAME"='DBMS_REGISTRY' OR                
              "OBJECT_NAME"='DBMS_STANDARD')                                              

1
Що відбувається в Oracle, якщо у вас є понад 3 значення, які ви тестуєте? Чи знаєте ви, чи Oracle не в змозі виконати таку ж оптимізацію бінарного пошуку, як MySQL, чи вона виконує її в обох випадках?
Марк Байєрс

2
@Mark Byers: Я спробував той самий запит з 10 значеннями, все одно той же результат. Зауважимо, що оптимізатор вдавав мої значення в алфавітному порядку. Я не був би здивований, якби Oracle зробив якусь внутрішню оптимізацію цього фільтра ...
Пітер Ленг,

5
Oracle також має INLIST ITERATORоперацію, яку він би вибрав, якби був індекс, який він міг би використовувати. Все-таки, коли я спробував це, і те, INі в ORкінцевому підсумку з тим же планом виконання.
Черан Шунмугавель

7

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

Ось як те, що ви можете використовувати з ІЛИ, але які не сумісні з IN: більше. більший чи рівний, менший, менший чи рівний, LIKE та ще щось подібне до оракула REGEXP_LIKE. Крім того, врахуйте, що умови не завжди можуть порівнювати одне і те ж значення.

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

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


6

Я думаю, що oracle досить розумний, щоб перетворити менш ефективний (залежно від того, що є) в інший. Тому я думаю, що відповідь має скоріше залежати від читабельності кожного (де я думаю, що це INявно перемагає)


2

OR має сенс (з точки зору читабельності), коли порівняно менше значень. INкорисний esp. коли у вас є динамічне джерело, з яким потрібно порівнювати значення.

Інша альтернатива - використання a JOINз тимчасовою таблицею.
Я не думаю, що ефективність не повинна бути проблемою, якщо у вас є необхідні показники.


-2

Я зробив запит SQL у великій кількості АБО (350). Postgres роблять це 437,80 мс .

Використовуйте АБО

Тепер використовуйте IN:

Використовуйте IN

23.18ms


4
Це не зовсім те саме, оскільки ви використовували підзапит для пункту IN.
gliljas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.