НЕ слід уникати IN IN?


14

Серед деяких розробників SQL Server дуже поширена думка, що NOT INце дуже повільно , і запити повинні бути переписані, щоб вони повертали той же результат, але не використовували "злі" ключові слова. ( приклад ).

Чи є до цього правда?

Чи є, наприклад, якась відома помилка в SQL Server (яка версія?), Яка викликає запити, які використовують NOT INгірший план виконання, ніж еквівалентний запит, який використовує

  • LEFT JOINв поєднанні з NULLчеком або
  • (SELECT COUNT(*) ...) = 0в WHEREпункті?

7
Ця стаття є дуже неточною. "В" не "повинні запускати один і той же запит знову і знову для кожного рядка в TableOne". Плакат, здається, вірить, що IN/ NOT INзавжди буде реалізовуватися за допомогою вкладених циклів. І я поняття не маю, що stops SQL Server from creating a ‘plan’має означати.
Мартін Сміт

5
@Heinzi Ця стаття, на яку ви посилаєтесь, повинна загинути у вогні, вона повна дурниць. Як-от: "Для заміни IN ми використовуємо ВНУТРІШНЕ ПРИЄДНАННЯ. Вони фактично те саме". Проблема в тому, що вони не одне і те ж. Я б не довіряв тому, хто не знає базового SQL, тобто різниці між приєднанням та напівз'єднанням, аналізувати що-небудь про поведінку SQL-сервера.
ypercubeᵀᴹ

Відповіді:


14

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

DECLARE @Customers TABLE(CustomerID INT);

INSERT @Customers VALUES(1),(2);

DECLARE @Orders TABLE(OrderID INT, CustomerID INT, CompanyID INT);

INSERT @Orders VALUES(10,1,NULL),(11,NULL,5);

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

SELECT [NOT IN] = CustomerID FROM @Customers 
  WHERE CustomerID NOT IN (SELECT CustomerID FROM @Orders);

SELECT [NOT EXISTS] = CustomerID FROM @Customers AS c 
  WHERE NOT EXISTS (SELECT 1 FROM @Orders AS o
  WHERE o.CustomerID = c.CustomerID);

SELECT [EXCEPT] = CustomerID FROM @Customers
EXCEPT SELECT CustomerID FROM @Orders;

Результати:

NOT IN
------
                 -- <-- no results. Is that what you expected?

NOT EXISTS
----------
2

EXCEPT
------
2

Зараз також є деякі проблеми з продуктивністю, і я про них говорю в цій публікації в блозі . Залежно від даних та індексів, NOT EXISTSзазвичай , вони будуть перевершувати NOT IN, і я не знаю, чи може вона колись погіршитися. Слід також зазначити, що EXCEPTможна ввести чітку операцію сортування, тому ви можете отримати різні дані (знову ж таки, залежно від джерела). І що популярний LEFT OUTER JOIN ... WHERE right.column IS NULLзразок завжди найгірший виконавець.

У Мартіна Сміта є багато хорошої допоміжної інформації у своїй відповіді на ТА .

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