Чи має значення порядок приєднання в SQL?


189

Не зважаючи на ефективність, чи отримаю такий самий результат із запитів A і B нижче? Як щодо C і D?

-- A
select *
from   a left join b
           on <blahblah>
       left join c
           on <blahblan>


-- B
select *
from   a left join c
           on <blahblah>
       left join b
           on <blahblan>  

-- C
select *
from   a join b
           on <blahblah>
       join c
           on <blahblan>


-- D
select *
from   a join c
           on <blahblah>
       join b
           on <blahblan>  

11
Що <blahblah>? Ви приєднуєтесь до А до В та від А до С, чи приєднуєтесь до А до В та В до С?
beny23

2
Привіт Бені, код у моєму запитанні - це абстракція. Мене не хвилює приєднання A до B або A до C, я просто хочу знати, чи дасть такий синтаксис, що дасть однакові результати.
Просто учень

Відповіді:


225

Для INNERприєднання, ні, порядок не має значення. Запити будуть повертати однакові результати, якщо ви зміните свій вибір SELECT *на SELECT a.*, b.*, c.*.


Для ( LEFT, RIGHTабо FULL) OUTERприєднуються, так, порядок має значення - і ( оновлено ) речі набагато складніші.

По-перше, зовнішні з'єднання не є комутативними, тому a LEFT JOIN bне є такими, якb LEFT JOIN a

Зовнішні приєднання також не є асоціативними, тому у ваших прикладах, які передбачають обидва (комутативність та асоціативність) властивості:

a LEFT JOIN b 
    ON b.ab_id = a.ab_id
  LEFT JOIN c
    ON c.ac_id = a.ac_id

еквівалентно :

a LEFT JOIN c 
    ON c.ac_id = a.ac_id
  LEFT JOIN b
    ON b.ab_id = a.ab_id

але:

a LEFT JOIN b 
    ON  b.ab_id = a.ab_id
  LEFT JOIN c
    ON  c.ac_id = a.ac_id
    AND c.bc_id = b.bc_id

не рівнозначно :

a LEFT JOIN c 
    ON  c.ac_id = a.ac_id
  LEFT JOIN b
    ON  b.ab_id = a.ab_id
    AND b.bc_id = c.bc_id

Ще один (сподіваюся, простіший) приклад асоціативності. Подумайте про це як (a LEFT JOIN b) LEFT JOIN c:

a LEFT JOIN b 
    ON b.ab_id = a.ab_id          -- AB condition
 LEFT JOIN c
    ON c.bc_id = b.bc_id          -- BC condition

Це еквівалентно , щоб a LEFT JOIN (b LEFT JOIN c):

a LEFT JOIN  
    b LEFT JOIN c
        ON c.bc_id = b.bc_id          -- BC condition
    ON b.ab_id = a.ab_id          -- AB condition

тільки тому, що у нас є "приємні" ONумови. І те, ON b.ab_id = a.ab_idі c.bc_id = b.bc_idінше є контролем рівності і не передбачають NULLпорівнянь.

Ви навіть можете мати умови з іншими операторами або більш складні , такі як: ON a.x <= b.xабо ON a.x = 7або ON a.x LIKE b.xабо ON (a.x, a.y) = (b.x, b.y)і два запити будуть по- , як і раніше еквівалентні.

Якщо ж будь-який із них пов'язаний IS NULLабо функція, пов'язана з нулями COALESCE(), наприклад, якби умова була b.ab_id IS NULL, то два запити не були б еквівалентними.


3
Правильніше сказати, що зовнішнє з'єднання є асоціативним, доки жоден предикат не може бути задоволений рядком, у якому всі стовпці з однієї таблиці є НУЛЬНИМ, ніж говорити, що це асоціативно до тих пір, поки предикати не включають IS NULL або 'функція, пов'язана з нулями'. Можна легко уявити присудок, який задовольняє першому опису, але не останньому, як a.somecol > 0 OR b.someothercol > 0; асоціативність може бути невдалою для цієї умови.
Марк Амері

Але так, я думаю, що технічно правдиво сказати, що OUTER JOIN є асоціативним, доки присудок не задовольняє жодної з умов, які я тут описую: stackoverflow.com/questions/20022196/… (перша з яких також порушує асоціативність для INNER JOIN, але це такий дешевий і очевидний підхід до його розірвання, що, можливо, це не варто згадувати.) Також варто зазначити, що найпоширеніший вид ПРИЄДНАННЯ - ПРИЄДНАННЯ за зовнішнім ключем - не задовольняє жодної з цих умов і, отже, це приємно і асоціативно.
Марк Амері

1
@MarkAmery Дякую, мені важко було структурувати свої речення з цього приводу (і я вже відхилив цю відповідь твоєї;)
ypercubeᵀᴹ

ypercube У мене є INNER JOINі наступне LEFT JOIN. Чи працює так, що спочатку запит буде Filterзаписувати на базі, INNER JOINа потім буде застосовано LEFT JOINдо Filteredзаписів?
Мухаммед Бабар

Насправді, все приєднатися типи є асоціативними, як зазначено в стандарті SQL і в відповідно до математичними визначеннями асоціативності, але вони не з'являються асоціативно , оскільки перестановкою дужки вимагає переміщення ONпункт (тобто «приєднатися до специфікації») на нове місце . Це лише синтаксис. Якщо ви використовуєте реляційне позначення алгебри (де специфікація з'єднання розміщена нижче оператора з'єднання), то асоціативність стає більш очевидною. Ваш аргумент лише показує, що зовнішні з'єднання не є комутаційними , що правильно
Лукас Едер

4

для регулярних приєднань, це не так. TableA join TableBстворить той же план виконання, що і TableB join TableA(тому ваші приклади C і D були б однаковими)

для лівого і правого з'єднання це робить. TableA left Join TableBвідрізняється від TableB left Join TableA, АЛЕ його однакове, ніжTableB right Join TableA


4
Це стосується лише комутативності, але приклади запитання показують, що запитувач зацікавлений у асоціативності. Відповідь ypercube стосується обох.
Марк Амері

2

Якщо ви спробуєте приєднатися до C на полі від B, перш ніж приєднатися до B, тобто:

SELECT A.x, A.y, A.z FROM A 
   INNER JOIN C
       on B.x = C.x
   INNER JOIN b
       on A.x = B.x

Ваш запит не вдасться, тому в цьому випадку порядок має значення.


Так, це правильно, правильну відповідь слід внести до поправок.
Нір Пенгас

-2

Оптимізатор Oracle вибирає порядок приєднання таблиць для внутрішнього з'єднання. Оптимізатор вибирає порядок з'єднання таблиць лише у простих пропозиціях ВІД. Ви можете перевірити документацію на oracle на своєму веб-сайті. А для лівого, правого зовнішнього приєднання найбільш відповідна відповідь - це права. Оптимізатор вибирає оптимальне замовлення приєднання, а також оптимальний показник для кожної таблиці. Порядок приєднання може вплинути на те, який індекс є найкращим вибором. Оптимізатор може вибрати індекс як шлях доступу до таблиці, якщо це внутрішня таблиця, але не, якщо це зовнішня таблиця (і подальших кваліфікацій немає).

Оптимізатор вибирає порядок з'єднання таблиць лише у простих пропозиціях ВІД. Більшість приєднань, які використовують ключове слово JOIN, згладжуються на прості приєднання, тому оптимізатор вибирає їх порядок приєднання.

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

Вибираючи замовлення на приєднання, оптимізатор враховує: Розмір кожної таблиці Індекси, доступні в кожній таблиці, чи індекс в таблиці корисний для певного порядку приєднання Кількість рядків і сторінок, які потрібно сканувати для кожної таблиці в кожній таблиці приєднатися до порядку

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