Чи має значення порядок, де пропозиції мають значення в SQL?


121

Скажімо, у мене є таблиця з назвою PEOPLE3 стовпці ID, LastName, FirstName, жоден із цих стовпців не індексується.
LastNameє більш унікальним і FirstNameменш унікальним.

Якщо я виконую два пошуки:

select * from PEOPLE where FirstName="F" and LastName="L" 
select * from PEOPLE where LastName="L" and FirstName="F"

Моє переконання, що другий швидше, тому що більш унікальний критерій ( LastName) стає першим у whereпункті, і записи будуть ліквідовані ефективніше. Я не думаю, що оптимізатор досить розумний, щоб оптимізувати перший sql.

Чи правильно я розумію?


8
Ні, цей порядок не має значення - будь-який гідний оптимізатор запитів розгляне всі пункти WHERE і
вигадає

3
Які були ваші спостереження, коли ви оприлюднили ці дві заяви? Як виглядали плани виконання?
Конрад Фрікс

3
Ви маєте на увазі конкретну RDBMS? Дійсно існують відмінності.
Бьорн


Відповіді:


101

Ні, цей порядок не має значення (або принаймні: не має значення).

Будь-який гідний оптимізатор запитів розгляне всі частини WHEREпункту і вигадає найефективніший спосіб задоволення цього запиту.

Я знаю, що оптимізатор запитів SQL Server підбере відповідний індекс - незалежно від того, в якому порядку у вас є дві умови. Я припускаю, що інші RDBMS матимуть подібні стратегії.

Важливо, чи є у вас відповідний індекс для цього чи ні!

У випадку з SQL Server, ймовірно, буде використаний індекс, якщо у вас є:

  • індекс на (LastName, FirstName)
  • індекс на (FirstName, LastName)
  • індекс просто (LastName), або просто (FirstName)(або обидва)

З іншого боку - знову ж таки для SQL Server - якщо ви використовуєте SELECT *для захоплення всіх стовпців із таблиці, а таблиця досить мала, то є хороший шанс, що оптимізатор запитів просто виконає сканування таблиці (або кластерного індексу) замість використання індекс (тому що пошук на повній сторінці даних для отримання всіх інших стовпців просто дуже дорого коштує дуже швидко).


Якщо немає індексів, то оп може бути правильним, залежно від даних. Звичайно, робити щось подібне без індексів, було б дивним рішенням ...
Тоні Хопкінсон,

@TonyHopkinson: Я не думаю, що навіть без індексів я сумніваюся, що взагалі є якась різниця. Зрештою: без індексів, що ще, окрім повного сканування таблиці, може зробити RDBMS, насправді ??
marc_s

2
Цікава сторона на SQL-сервері, очевидно, порядок НЕ ІСНУЄ в межах предикатів насправді може вплинути на створення плану: bradsruminations.blogspot.com/2010/04/looking-under-hood.html
Джастін Сварцель

3
Дивна річ у тому, що при першому виконанні запиту порядок умов у пункті WHERE МАЄ ЗНАЧЕННЯ! У мене було дві умови, щось на кшталт: WHERE T1.col_1/T2.col_2 > 10 AND T2.col_2 <> 0і я отримав DIVIDE BY 0помилку. Після того як я переключив замовлення, умови запиту виконали успішно. Тоді я переключив замовлення назад, так що я би сподівався знову отримати помилку, але цього разу воно спрацювало! Зрештою, я зробив висновок, що для першого запуску значення має значення, доки не буде побудований план виконання. Після цього замовлення не буде "Неважливо", тому що план оптимізатора / exec подбає про це
Radu Gheorghiu

1
Мені подобається, що ти сказав: "... або принаймні: не має значення" - я повністю згоден. Іноді це має значення, на жаль. Я бачив випадки, коли SQL був надто складним, щоб оптимізатор міг обробляти, і такі речі, як порядок стовпців та порядок приєднання до таблиці, мали значення. Це залежить від RDBMS, складності оператора SQL і навіть випуску. Дуже складний SQL може призвести до неправильних рішень оптимізатора або використання жорсткого коду за замовчуванням в коді оптимізатора.
Віктор Ді Лео

19

Порядок пропозицій WHERE не повинен змінювати базу даних, яка відповідає стандарту SQL. Порядок оцінювання не гарантується в більшості баз даних.

Не думайте, що SQL дбає про порядок. Далі створюється помилка в SQL сервері:

select *
from INFORMATION_SCHEMA.TABLES
where ISNUMERIC(table_name) = 1 and CAST(table_name as int) <> 0

Якщо перша частина цього пункту була виконана спочатку, тоді лише імена числових таблиць будуть видані як цілі числа. Однак це не вдається, наводячи чіткий приклад того, що SQL Server (як і в інших базах даних) не піклується про порядок пропозицій у операторі WHERE.


Що це за запит, що викликає помилку, пов'язаний з порядком оцінки дериката предикату?
Джим

7
@Jim Якби ISNUMERIC(table_name) = 1оцінювали спочатку, то тоді CASTколись називали б лише імена числових таблиць. Але оскільки він не оцінюється спочатку, CASTвін також оцінюється для нечислових імен таблиць, а також викликає повідомлення про помилку.
hibbelig

2
Відмінне уточнення
neeohw

Щоб бути впевненим, я перевірив, чи змінити умови призведе до того, що SQL-сервер обробляє їх навпаки, але це не дає обох способів. Я думаю, що це може означати будь-яку з двох речей: (1) Це не оптимізація так добре, як це могло б, або (2) Це помилка часу компіляції, і SQL навіть не починає намагатися порівняти що-небудь, збираючи попереднє. Я здогадуюсь що це nr. 2.
Луї Сомерс

9

Проект ANSI SQL 2003 5WD-01-Framework-2003-09.pdf

6.3.3.3 Порядок оцінки правил

...

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

скопійовано звідси


2

Ні, всі RDBM спершу починаються з аналізу запиту та оптимізації його, переупорядковуючи пункт your where.

Залежно від того, який RDBM ви використовуєте, можна відобразити результат результату аналізу (наприклад, шукайте план пояснення в Oracle, наприклад)

М.


Це робиться на основі індексів. Тож це непряме за змістом.
Тоні Хопкінсон

1

Оригінальна заява про ОП

Я вважаю, що другий швидше, тому що більш унікальний критерій (LastName) виходить на перше місце в пункті "де", і записи будуть ліквідовані більш ефективно. Я не думаю, що оптимізатор> досить розумний, щоб оптимізувати перший sql.

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

BTW, для вищезгаданих двох запитів оптимізатор сервера SQL не буде робити жодної оптимізації, але буде використовувати план Trivila до тих пір, поки загальна вартість плану буде меншою, ніж порогова вартість паралелізму.


0

Це правда, наскільки це йдеться, якщо вважати, що імена не індексуються. Однак різні дані помиляються. Для того, щоб з'ясувати, яким способом це зробити, який може відрізнятись кожен раз, СУБД повинна буде запустити окремий запит підрахунку для кожного стовпця та порівняти числа, що коштуватиме більше, ніж просто знизати плечима та почати з цим.

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