Використовуючи ключове слово JOIN чи ні


45

Наступні SQL запити такі самі:

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

І, безумовно, результат однакових планів запитів у всіх СУБД, які я коли-небудь пробував.

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

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

Чи одна з цих форм об'єктивно краща за іншу? Якщо ні, то які причини будуть використовувати одне над іншим?


1
Чому б не проаналізувати це і не повідомити іншим про результат? Взагалі, продуктивність дуже переважає стильову перевагу.
Дем'ян Брехт

3
"приводять до тих самих планів запитів у всіх СУБД, які я коли-небудь пробував" Якби це могло відповісти з точки зору продуктивності, воно запитало б його на stackoverflow.com. на жаль, це той самий запит.
SingleNegationElimination

Ах .. Пропустив це :)
Дем'ян Брехт

2
"Суб'єктивний" не означає "яка ваша думка". Я редагував це свого роду відповідають критеріям , викладені в FAQ .
Aaronaught

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

Відповіді:


60

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

Наприклад, візьміть такий запит:

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

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

Однак тепер візьміть цей код:

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

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


Це єдиний розумний спосіб зробити це, особливо коли ви пройдете дві таблиці або вам потрібно поєднання лівого, правого та повного приєднання.
aglassman

5
+1 Для "роз'єднання питань" приєднується об'єднання даних, де пункти диктують підмножини даних, які вас цікавлять.

39

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

По-перше, коли ви отримуєте складніші запити, дуже легко зробити випадкове перехресне з'єднання, пропустивши умову де. Це те, що явний синтаксис приєднання може запобігти тому, що ви отримаєте помилку синтаксису.

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

Тоді виникає проблема лівого і правого з'єднань, які є проблематичними принаймні в деяких dbs за допомогою неявного синтаксису. Вони застаріли в SQL Server і насправді не повертають правильних результатів надійно навіть у старих версіях. Жоден запит, який потребує зовнішнього з'єднання, не повинен містити неявного синтаксису в SQL Server.

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

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


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

8

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

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

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

Слід зазначити, що поведінка за замовчуванням є однаковою в будь-якому випадку, і щоб отримати альтернативні плани, потрібно знати внутрішні характеристики dbms та особливості відповідних таблиць, щоб отримати інший результат


2
Однак ви трохи не зрозуміли ці документи. По-перше, насправді є три пороги. Один розстрілює GEQO, як ви вказали; інші два (від та приєднати межі згортання) в кінцевому підсумку змушують планувальник дотримуватися вибору відповідних індексів, а не переорганізувати порядок з'єднання. По-друге, і так само важливо, що запити переписуються під час їх розбору. Це призводить до того, що перший із прикладних запитів розбирається в точно такому ж дереві запитів, що і у другому - пороги потім повідомляють PG, чи слід спробувати переупорядкувати приєднання чи ні.
Дені де Бернарді

8

Ну ось вигляд теорії множин про це:

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

Тепер, якщо ви щось записуєте в пункті де, це як встановити умову на цю "конкатенацію", вказуючи, які рядки "з'єднати" з якими рядками.

Це насправді "приєднання" до рядків :), а отже, ключове слово приєднання, яке допомагає надати більш читабельний синтаксис і зрозуміліше, що ви "справді" хочете приєднатися до деяких загальних значень. Подібно до того, що @Dustin уточнив вище.

Тепер кожна СУБД є розумною, тобто вона не розраховує декартовий продукт спочатку, а потім фільтрує дані (вкрай марнотратні), а робить це, грунтуючись на структурі запитів. Єдине, про що я можу придумати, - це коли ви попросите його "приєднатися" - це як зробити явну активність приєднання явною і, ймовірно, допомагає запустити код швидше (на скільки? Вам доведеться профайлювати його і побачити), але в Випадок, розділений комами, йому потрібен певний час, щоб «розібратися» в оптимальній стратегії. Я можу помилятися, але я просто роблю освіту здогадуватися про те, як можна було б кодувати це ...


5

Я думаю, що для цього випадку краще використовувати заяви JOIN.

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


3

Будь-яка RDBMS змусить їх зробити те саме, що стосується виконання. Це зводиться до того, чи можна читати і виразніше.

Використовуйте ПРИЄДНАЙТЕСЬ, щоб було зрозуміло, що таке відповідність приєднання та що таке фактичний вибір, як у:

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

vs.

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

Останній випадок відразу дає зрозуміти, яка умова приєднання, а що є критерієм відбору.


1

Я лише коли-небудь бачив, що це призводить до різного набору оптимізацій, і якщо пам'ять слугує, це було в ms-sql2k за дійсно волохатим запитом. У цьому прикладі стара форма, що використовується з * =, призвела до приблизно в 4 рази швидшої продуктивності. Ніхто, включаючи наших технічних хлопців Microsoft, ніколи не міг пояснити, чому. Хлопці з МС позначили це помилкою. Я його більше ніколи не бачив.

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


Звичайно, лівий синтаксис приєднання ніколи не забезпечував правильних результатів надійно (див. BOL для SQL Server 2000), тому навіть якби він був швидшим, я би замінив його.
HLGEM

Я ніколи з цим не стикався, а пошук зірочкою ніколи не закінчується добре, чи є у вас приклад?
Білл

-1

Старий стиль застарілий, його не слід використовувати.

Навіть не повинно бути аргументу щодо того, хто краще чи ні. Новий код не повинен використовувати старий синтаксис.


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

1
@RemcoGerlich, чому це було знято, тут не обговорюється. Тут обговорюється питання використання старого чи нового синтаксису. Незалежно від того, що краще, ніж інше, чи ні, це суперечка: не слід використовувати старий синтаксис. Питання чому - це ще одне обговорення. (той, який оселився 20 років тому.)
Пітер Б

-4

Однією з причин більш короткого синтаксису є те, що він більш лаконічний, тому, якщо вам це зручно, читати простіше. Я вважаю, що багатослівний випадок схожий на виписування арифметики в COBOL, наприклад, МНОГО A B B DOWING C.


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