Чи є істотна різниця між запитами, приєднаними до пунктів WHERE, та запитами, що використовують фактичний приєднання?


32

У Learn SQL The Hard Way (вправа шість) автор подає наступний запит:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

і далі каже, що:

Насправді є й інші способи змусити такі запити працювати під назвою "приєднується". Я зараз уникаю цих концепцій, бо вони шалено заплутані. Просто дотримуйтесь цього способу приєднання таблиць зараз і ігноруйте людей, які намагаються сказати [ви], що це якось повільніше або "низький клас".

Це правда? Чому або чому ні?


3
Я не думаю, що це є, але ви можете спробувати зробити ПОЯСНЕННЯ, щоб побачити, чи є різниця у виконанні запиту.
гросмайстерB

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

7
ПРИЄДНАЙТЕСЬ дуже добре транспортує наміри (приєднуючись до таблиць), це залишає частину WHERE для фактичних фільтрів і полегшує її читання. (крім maaany інших наслідків)
Th 00 mÄ s

2
Ви вивчаєте SQL по важкому шляху, якщо автору не можна заважати писати прості приєднання! Як каже ThomasS, використовуючи JOIN, наміри стають зрозумілішими, а пункти WHERE стають набагато простішими. Також використання JOIN краще ілюструє теорію множин, яка лежить в основі SQL.
Деніел Холлінрак

1
Не впевнений, як я ставлюсь до чогось, що ніби навчить вас чомусь, кажучи: "Але ей, ми збираємось пропустити цю основоположну концепцію, тому що це craaazzzyyyy банани". Думаю, я б шукав іншого джерела, на якому слід навчитися. У якийсь момент вам потрібно буде зробити зовнішні з'єднання та перехресні з'єднання, і ви повинні знати, як їх робити.
Моріс Рівз

Відповіді:


23

З авторським підходом викладати ЗОВНІШНІ ПРИЄДНАННЯ буде набагато складніше. Пункт ON у програмі INNER JOIN ніколи не вражав мене, як і багато інших речей. Можливо, це тому, що я ніколи не навчився старого. Мені б хотілося подумати, що є причина, що ми її позбулися, і це не бути самовдоволеним і називати цей метод низьким класом.

Це правда у дуже вузькому сценарії, який автор створив:

  • Такий вхідний рівень SQL, що використання ON, є складним
  • Тільки з огляду на ПРИЄДНАЙТЕСЬ / ВНУТРІШНЕ ПРИЄДНАННЯ, а не на ВІДНІШНІ ПРИЄДНАННЯ
  • Ізольований кодер, який не повинен читати чужий код, а також не має людей, які мають досвід читання / використання кодового режиму ON.
  • Не вимагає складного запиту з великою кількістю: таблиць, якщо є, але є і або.

Я вважаю, що як частина прогресивної роботи у навчанні, простіше її зруйнувати та мати природний прогрес:

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

Концепції приєднання та фільтрування таблиць насправді не однакові. Вивчення правильний синтаксис тепер матиме більше Перехідний , коли ви дізнаєтеся OUTER JOINS якщо автор не має наміру на навчання застарілі / застарілі речі , як: *= or =*.


5
Причина JOIN була додана через те, що не було стандарту для вираження зовнішніх приєднань, тому кожен постачальник баз даних мав для цього свій "спеціальний" (несумісний) синтаксис. IIRC Oracle мав *=або =*вказує ліве або праве зовнішнє з'єднання, ще одне я використовував лише підтримувані ліві зовнішні з'єднання за допомогою |=оператора.
TMN

1
@TMN IIRC Oracle використано +=чи, можливо, було =+. Я вважаю, *=був Transact-SQL (Sybase і пізніше MS-SQL). Все-таки хороший момент.
Девід

1
Там, де це починає ускладнюватися (IMHO) - це коли ви поєднуєте внутрішнє і зовнішнє з'єднання. У такому типі ситуації, зізнаюся, іноді я повертаюсь до "низького класу" техніки виконання своїх приєднань до WHEREпункту. (Я чув, що це згадується як тета-приєднання , але я не впевнений, чи це правильно.)
Давид

Оператори IIRC на кшталт "більший за" або "рівний" іноді називали "операторами тети", але пошук в google призводить до деякої операції в обчисленні.
Вальтер Мітті

12

Чи буде це повільніше, залежить від оптимізатора запитів та того, як він впорядковує запит (те, що ви пишете, насправді не те, що виконується). Однак велика проблема цієї цитати полягає в тому, що вона повністю ігнорує той факт, що існують різні типи з'єднань, які діють абсолютно по-різному. Наприклад, те, що говориться, теоретично відповідає дійсності inner joins, але це не відповідає дійсності для outer joins( left joinsі right joins).


9
+1 Для інших типів приєднань. Більшість моїх приєднань є INNER JOINабо LEFT OUTER JOIN. Вони не "шалено заплутані". SQL може бути шалено заплутаним, але це не приклад цього.
mgw854

по темі , але якщо заяву бути різними типами приєднатися до S або типів приєднатися ?
user1451111

9

Автор представляє простий випадок, коли можна використовувати або старий, або новий синтаксис. Я не погоджуюся з його твердженням про те, що приєднання є шалено заплутаним, тому що приєднання до таблиць є фундаментальною концепцією запитів SQL. Тож, можливо, автору довелося б витратити певний час, щоб пояснити, як ПРИЄДНАТся, перш ніж виголосити висловлене твердження, а також зробити приклад запиту з декількох таблиць.

Слід використовувати новіший синтаксис. Основним аргументом для цього є те, що ваш запит матиме:

  • Виберіть критерії
  • Приєднуйтесь до критеріїв
  • Критерії фільтра

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

Також декартовий продукт можна отримати, забувши критерії приєднання у пункті про фільтр:

 person_pet.person_id = person.id

використовуючи старіший синтаксис.

Використання нового синтаксису також визначає, як має відбуватися з'єднання, що важливо щодо того, чи хочете ви INNER, LEFT OUTER тощо, тому це більш чітко щодо синтаксису JOIN, який IMHO збільшує читабельність для незнайомих людей з таблицями приєднання.


5

Не повинно бути, аналізатор запитів повинен генерувати еквівалентне внутрішнє представлення для еквівалентних запитів незалежно від того, як вони написані. Автор просто використовує синтаксис pre-SQL-92, і саме тому він згадує, що його можна розглядати як "старомодний" або "низький клас". Всередині аналізатор та оптимізатор повинні генерувати один і той же план запитів.


5

Я вивчив SQL таким чином, включаючи *=синтаксис зовнішніх приєднань. Для мене це було дуже інтуїтивно, оскільки всі відносини мали рівноправний пріоритет і краще працювали над створенням запитів у вигляді серії запитань: Що ви хочете? Звідки ви їх хочете? Яких ти хочеш?

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

Принаймні, у MSSQL немає суттєвої різниці у виконанні запитів, якщо ви використовуєте те саме замовлення приєднання. Однак, існує одна чітка, величезна проблема щодо вивчення (та використання) SQL таким чином. Якщо ви забудете одне зі своїх стосунків, ви отримаєте несподівані перехресні продукти. Що в базі даних будь-якого нетривіального розміру є надмірно дорогим (і небезпечним для невідбірників!). Набагато складніше забути відношення при використанні joinсинтаксису стилів.


7
Це реляційна база даних, тому відносини є досить важливими для запиту. Особисто мені важче зрозуміти запит, який змішує справжні фільтри (foo.x = 5) з відносинами (foo.x = bar.x). Двигун може легко оптимізувати це до об'єднання, але людина, по суті, має міркувати про це рядково за рядком, на відміну від наборів та підмножин.
Aaronaught

4

Слід враховувати два різні аспекти цього: Продуктивність та ремонтопридатність / читабельність .

Ремонтопридатність / читабельність

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

Що вам краще виглядає і читання?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

Або ...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

Особисто для мене перший є досить читабельним. Ви бачите, що ми з’єднуємо таблиці з INNER JOIN, тобто означає, що ми тягнемо рядки, які відповідають наступному пункту приєднання (тобто "приєднати працівника до EmployeeDepartmentHistory на BusinessEntityID та включити ці рядки").

Останнє, кома для мене нічого не означає. Мене змушує замислитися, що ви робите з усіма цими WHEREпредикатами пункту.

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

Насправді існують інші способи залучення таких запитів до роботи під назвою "приєднується"

Всі вони приєднуються. Навіть коми - це з'єднання. Те, що автор не називає їх, справді є їхнім падінням .... це не очевидно. Це повинно бути очевидним. Ви приєднання реляційних даних, будь то вказати вам JOINабо ,.

Продуктивність

Це, безумовно, буде залежати від RDBMS. Я можу говорити лише від імені Microsoft SQL Server. Це дуже рівнозначно. Звідки ти знаєш? Захопіть плани після виконання та подивіться, що саме робить SQL Server для кожного з цих операторів:

введіть тут опис зображення

У наведеному вище зображенні я підкреслив, що я використовую обидва запити, як зазначено вище, і відрізняються лише явними символами для приєднання ( JOINvs ,). SQL Server робить те саме.

Підсумок

Не використовуйте коми. Використовуйте явні JOINтвердження.


Я дізнався INNER JOINs задовго до того, як зрозумів, що варіант із пунктами WHERE рівноцінний, і обидва ваші приклади виглядають для мене дуже читабельними. Той, де ВІД і комами, може бути ще читабельнішим. Я думаю, де воно падає у великих складних запитах, а не в порівняно простих.
Роберт Харві

Справа в тому, що думати, що зміна комами не є реляційним приєднанням, зовсім не правильно.
Томас Стрінгер

Я думаю, ви неправильно трактуєте коми як приєднання. Коми - це просто окремі таблиці; це умови, де створюються з'єднання, а не коми.
Роберт Харві

1
Я напевно можу сказати, що немає приєднання до того, що відбувається в предикатних застереженнях. Я думаю, ви неправильно інтерпретуєте конструкції реляційного запиту. Ви спробували приєднатись до кома без пунктів WHERE? Це все ще працює. Це декартовий приєднання. Як ви думаєте, що ви отримуєте за допомогою коми? Не кажіть, що ви намагаєтеся зберегти символи.
Томас Стрінгер

1
Я б сказав, що перший краще, тому що ваші наміри ясніші. Неясності набагато менше.
Даніель Холлінрак

4

Ні, це зовсім неправда. Автор налаштовує своїх читачів на плутанину та заохочує програмування культового культу, що дозволяє уникнути дуже потужної структурної різниці між стандартним синтаксисом та цим старішим варіантом, який він вважає за краще. Зокрема, затиснутий пункт WHERE ускладнює з'ясування того, що робить його запит особливим.

Його приклад спонукає читача створити розумову карту її значення, яка має надзвичайно безлад.

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

Приблизно вище:

Отримайте ідентифікатор домашнього улюбленця, ім’я, вік і загибель для всіх домашніх тварин, person_pet та осіб, у яких ідентифікатор домашнього улюбленця збігається з pet_id person_pet, а person_id цього запису відбувається у відповідності з person_id людини, якій FIRST_NAME є "Zed"

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

Існує причина, чому приєднання є загальними, і це стара класична канарка "відокремлення проблем". Зокрема, для SQL-запиту є вагомі підстави відокремити, як структуруються дані щодо того, як фільтруються дані.

Якщо запит написано чистішим, наприклад

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

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


Звичайно, жодна сучасна система баз даних не повинна бачити змістовної різниці між двома стилями. Але якби продуктивність бази даних була єдиною увагою, запит SQL також не мав би простору чи великої літери.


2
Оскільки я вже кілька разів чув цей рефрен, дозвольте мені зіграти захисника диявола. Дізнайтеся, що Х важкий шлях полягає у технічній глибині; той, хто добре розуміє SQL, дійсно повинен знати, що два підходи є рівнозначними з точки зору виробленого ними продукту.
Роберт Харві

1
Я бачу це, але автор не просто стверджує, що вони є еквівалентними висловлюваннями на гідному сервері SQL; вони стверджують, що використання JOIN "заплутане", це шлях, який очікує брудний код. ("Ні, не використовуйте LINQ, просто напишіть свою заяву FOR вручну." "Компілятору не важливо, як я називаю цей метод, тому немає ніяких причин не називати його FN1")
DougM

3

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

Потрібно спочатку навчити базовим поняттям баз даних, а потім показати SQL як один із способів їх опису.

Ліві та праві з'єднуються, можна стверджувати, що вони не мають великого значення. Зовнішнє приєднання, ви можете використовувати старий *=і =*синтаксис.

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


3
"Навчіться Х важким шляхом" - це інший підхід до навчання. Ви пишете код, а потім розумієте його.
Роберт Харві

7
@RobertHarvey Це не інший підхід до навчання, його стандартний. Пізніше це трапляється лише в тому випадку, якщо ви все ще залишаєтесь на місці, коли колеса зійдуть. стикалися з тим, що надто багато людей пише SQL, які думають, що таблиця є прямокутним масивом комірок, щоб мати певну впевненість у цьому методі.
Тоні Хопкінсон

2

Приклад еквівалентний простому переформулюванню з внутрішніми JOIN. Різниця полягає лише у додаткових можливостях, які дозволяє синтаксис JOIN. Наприклад, ви можете вказати порядок, в якому обробляються стовпці двох таблиць; див., наприклад, https://stackoverflow.com/a/1018825/259310 .

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


Хороша відповідь, хоча ви використовуєте WHEREабо ставите додаток у JOINвиписці, насправді може мати вплив на ефективність залежно від оптимізатора запитів. Я бачив це не раз.
Локк

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

2

Коли я засвоїв SQL, форми INNER JOIN, LEFT JOIN тощо не існували. Як уже було сказано в інших відповідях, різні діалекти SQL мали кожен реалізований зовнішній приєднання, використовуючи ідіосинкратичний синтаксис. Це пошкодило портативність коду SQL. Зновлення мови разом вимагало певних змін, і ліве приєднання тощо було те, на чому вони вирішили.

Це правда, що для кожного INNER JOIN може бути записана еквівалентна кома з умовою приєднання в пункті WHERE. Мені знадобилося певний час, щоб перейти від подобається старої форми до переваги нової форми. Мабуть, автор Learning SQL The Hard Way все ще вважає, що старий спосіб простіше.

Чи є відмінності? Ну так, є. Перший полягає в тому, що INNER JOIN з пунктом ON розкриває наміри автора чіткіше, ніж старий стиль. Більш очевидним є той факт, що пункт ON є фактично умовою приєднання, а не якимсь іншим видом обмеження. Це робить код, який використовує INNER JOIN, легше засвоїти при читанні, ніж старий стиль. Це важливо при збереженні чужого коду.

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

Третя відмінність полягає в тому, що коли ви навчаєтесь, використовуючи INNER JOIN (або просто звичайний ПРИЄДНАЙТЕСЬ), це полегшує навчання LEFT JOIN тощо.

Крім цього взагалі немає матеріальної різниці.


0

Це залежить, якщо ви думаєте з точки зору множин та формальної логіки .....

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

Але якщо ви, як 99% людей, вам не сподобалася формальна логіка в ступені вашої математики, то ключове слово приєднання - це легше вивчити. SQL раніше був представлений в університеті як просто певний спосіб записувати формальні логічні запити ....

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