Яка різниця між НЕ ІСНУЄТЬСЯ проти НЕ ВІД І НАЛЕВОМ ПРИЄДНАЙТЕСЬ, ЩО НУЛЬТЕ?


151

Мені здається, що ви можете зробити те ж саме в SQL-запиті, використовуючи або НЕ ІСНУЄТЬСЯ, ні ВНУТЬ, або ВЛІТТЕ ПРИЄДНАЙТЕСЬ, ЩО НУЛЬНО. Наприклад:

SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)

SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)

SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL

Я не впевнений, чи правильний синтаксис я правильний, але це загальні методи, які я бачив. Чому я вирішив використовувати один над іншим? Чи відрізняється продуктивність ...? Який із них найшвидший / найефективніший? (Якщо це залежить від впровадження, коли я буду використовувати їх?)


6
Багато поширених двигунів SQL дають вам можливість бачити план виконання. Ви можете часто помітити значні відмінності в ефективності для логічно еквівалентних запитів таким чином. Успіх будь-якого методу залежить від таких факторів, як розмір таблиці, які показники присутні та інші.
Кріс Фармер

2
@wich: жодна база даних не піклується про те, що саме ви повертаєтесь у EXISTSпункті. Ви можете повернутися *, NULLабо що завгодно: все це буде оптимізовано.
Quassnoi

2
@wich - чому? І те й інше : techonthenet.com/sql/exists.php і ось тут: msdn.microsoft.com/en-us/library/ms188336.aspx, здається, використовується * ...
froadie

8
@wich: мова не йде про "вираження інтересу". Це стосується того, що аналізатор запитів вимагає, щоб ви щось помістили між SELECTі FROM. І *просто простіше набрати. Так, SQLчи є схожа з природною мовою, але вона розбирається і виконується машиною, запрограмованою машиною. Справа не в тому, що він коли-небудь раптом увірветься у вашу кабінку і кричить "перестаньте вимагати додаткових полів у EXISTSзапиті, тому що мені боляче розбирати їх, а потім викидати їх!". З комп’ютером все гаразд.
Quassnoi

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

Відповіді:


139

Коротко:

NOT INдещо інше: воно ніколи не відповідає, якщо є лише одне NULLв списку.

  • В MySQL, NOT EXISTSтрохи менш ефективний

  • В SQL Server, LEFT JOIN / IS NULLменш ефективний

  • В PostgreSQL, NOT INменш ефективний

  • У Oracle, всі три методи однакові.


1
Дякуємо за посилання! І дякую за швидкий огляд ... Мій офіс чомусь блокує посилання: P, але я перевірю це, як тільки перейду до звичайного комп’ютера.
froadie

2
Інша справа, що якщо table1 .aмістить запит не повернеться цей рядок , але і зробить запит , якщо порожньо. НЕ ВІД НЕ ІСНУЄ НУЛЬБАЛЬНІ стовпці: SQL ServerNULLEXISTSNOT INtable2
Мартін Сміт

@MartinSmith: NULL NOT IN ()оцінює справжнє (не NULL) так само, якNOT EXISTS (NULL = column)
Quassnoi

2
@Quassnoi - е, Добре, зрозуміло, що це неправильно. NOT EXISTSЗавжди буде повертати рядок , але NOT INбуде робити це тільки якщо суб - запит не повертає ні однієї рядки.
Мартін Сміт

5

Якщо база даних добре оптимізує запит, два перші будуть перетворені на щось близьке до третього.

Для простих ситуацій, таких, як у вас, про які ви питаєте, має бути незначна різниця, оскільки всі вони виконуватимуться як з'єднання. У більш складних запитах, база даних може бути не в змозі зробити приєднатися з ряду not inі not existsqueryes. У такому випадку запити будуть набагато повільніше. З іншого боку, приєднання також може бути поганим, якщо немає індексу, який можна використати, тому що лише тому, що ви використовуєте приєднання, це не означає, що ви в безпеці. Вам доведеться вивчити план виконання запиту, щоб визначити, чи можуть виникнути проблеми з ефективністю.


2

Якщо припустити, що ви уникаєте нулів, то це всі способи написання антиприєднання за допомогою Standard SQL.

Очевидним упущенням є еквівалент із використанням EXCEPT:

SELECT a FROM table1
EXCEPT
SELECT a FROM table2

Зауважте, що в Oracle вам потрібно використовувати MINUSоператор (можливо, краще ім’я):

SELECT a FROM table1
MINUS
SELECT a FROM table2

Якщо говорити про фірмовий синтаксис, можливо, також існують нестандартні еквіваленти, які варто вивчити залежно від продукту, який ви використовуєте, наприклад, OUTER APPLYу SQL Server (щось подібне):

SELECT t1.a
  FROM table1 t1
       OUTER APPLY 
       (
        SELECT t2.a
          FROM table2 t2
         WHERE t2.a = t1.a
       ) AS dt1
 WHERE dt1.a IS NULL;

0

Коли потрібно вставити дані в таблицю з багатопольовим первинним ключем, врахуйте, що це буде набагато швидше (я намагався в Access, але я думаю, в будь-якій базі даних) не перевіряти, що "в таблиці немає записів із" такими "значеннями", - досить просто вставити в таблицю, і зайві записи (за ключем) не будуть вставлені двічі.


0

Перспектива ефективності завжди уникає використання зворотних ключових слів, як НЕ, НЕ ІСНУЄТЬСЯ, ... Оскільки для перевірки обернених елементів СУБД потрібно пропустити всі наявні та відкинути обернену вибірку.


1
А що ви пропонуєте як вирішення, коли вам насправді потрібно NOT?
dnoeth

Добре, коли немає жодної можливості причини, нам потрібно використовувати НЕ операції, і тому вони існують. Найкраща практика - це уникати їх, коли у нас є інші альтернативні рішення.
Лахіру Курай

@onedaywhen, якщо оптимізатор перетворює запит, і він повертає неправильний результат, тоді це помилка
David דודו Markovitz

@DuduMarkovitz: так, і якщо ви звертаєтесь до команди SQL Server, і вони визнають помилку, але відмовляються виправляти її, оскільки, за їх словами, це може робити запити повільніше, тоді це проблема, з якою вам потрібно боротися .
день, коли

@onedaywhen - Це не гіпотетичний сценарій, я припускаю :-) Ви випадково пам'ятаєте деталі про помилку?
Девід דודו Markovitz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.