Зазвичай, коли я пишу програму і використовую умови, наприклад: if (${condition1} && ${condition2})
, я звик ставити умови, які легше перевірити і які можуть завершити виконання раніше, на початок, а більш ресурсоємні умови — на кінець, щоб підвищити ефективність виконання.
Але чи працює це так у SQL? Чи виконуються умови в WHERE-перевірці також зліва направо? Відповідь така:
Не завжди. Це визначається планом виконання, який складає компонент під назвою Optimizer.
Цю особливість я помітив, коли на роботі змінив середовище виконання моєї збереженої процедури і отримав помилку, яку раніше не зустрічав.
Ось код, де сталася проблема:
select * from table1 t1
inner join table2 t2 on ...
where t1.ColName = 'ExpDatetime' --condition1
and t2.ColValue <> '' --condition2
and t2.ColValue < getdate() --condition3
З того, як я розташував умови, можна було б очікувати, що спочатку будуть фільтрувати записи, що задовольняють condition1, потім condition2, а вже потім — condition3. Тому що condition1 спочатку фільтрує дані, які можна перетворити на тип datetime, і лише після цього можна проводити порівняння за допомогою condition3.
Але, як я зазначив у вступі, оскільки Optimizer насправді вирішує, що виконати першим, в даному випадку він почав виконувати condition3. І це призвело до помилки Error: Conversion failed when converting date and/or time from character string
, оскільки деякі значення не могли бути перетворені в datetime.
Простими словами, щоб підвищити ефективність виконання, Optimizer перетворює SQL-запит в дерево, створює кілька планів виконання і вибирає той, який, на його думку, буде найефективніший. В результаті він визначає реальний порядок виконання запиту.
Цей випадок нагадує мені, що під час написання SQL-запитів потрібно завжди подумки перевіряти, чи є залежність між умовами в WHERE, чи їх порядок виконання не призведе до помилки, щоб уникнути подібних ситуацій у майбутньому.
Ось два способи вирішення цієї проблеми:
- Використовувати конструкцію
case when
, щоб явно вказати порядок виконання умов. - Виконати два етапи: спочатку отримати записи, що відповідають condition1 і condition2, і зберегти їх у тимчасовій таблиці, а потім провести порівняння для condition3 на цій таблиці.
Перекладено з: SQL Where 子句內的多條件會按照順序執行嗎?