Имеет ли значение порядок соединения в 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
Привет, Бени, код в моем вопросе - абстракция. Меня не интересует соединение А с В или А с С, я просто хочу знать, даст ли подобный синтаксис одинаковые результаты.
Просто ученик

Ответы:


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
Правильнее будет сказать, что внешнее соединение является ассоциативным, если ни один предикат не может быть удовлетворен строкой, в которой все столбцы из одной таблицы равны NULL, чем сказать, что оно ассоциативно, если предикаты не содержат IS NULL или «функция, связанная с нулями». Легко представить себе предикат, который удовлетворяет первому описанию, но не второму, как a.somecol > 0 OR b.someothercol > 0; ассоциативность может потерпеть неудачу для этого условия.
Марк Амери

Но да, я думаю, что технически верно сказать, что OUTER JOIN является ассоциативным, если предикат не удовлетворяет ни одному из условий, которые я здесь описываю: stackoverflow.com/questions/20022196/… (первое из которых также нарушает ассоциативность для ВНУТРЕННИХ СОЕДИНЕНИЙ, но это такой дешевый и очевидный подход к его взлому, что, возможно, не стоит упоминать.) Также стоит отметить, что наиболее распространенный вид СОЕДИНЕНИЯ - СОЕДИНЕНИЕ по внешнему ключу - не удовлетворяет ни одному из этих условий. и, таким образом, это приятно и ассоциативно.
Марк Амери

1
@MarkAmery Спасибо, мне было трудно структурировать свои предложения по этому вопросу (и я уже проголосовал за ваш ответ;)
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 выбирает порядок соединения таблиц для внутреннего соединения. Оптимизатор выбирает порядок объединения таблиц только в простых предложениях FROM. Вы можете проверить документацию оракула на их сайте. А для левого, правого внешнего соединения самый голосующий ответ - правильный. Оптимизатор выбирает оптимальный порядок соединения, а также оптимальный индекс для каждой таблицы. Порядок соединения может влиять на то, какой индекс является лучшим выбором. Оптимизатор может выбрать индекс в качестве пути доступа к таблице, если это внутренняя таблица, но не если это внешняя таблица (и дальнейших уточнений нет).

Оптимизатор выбирает порядок объединения таблиц только в простых предложениях FROM. Большинство объединений с использованием ключевого слова JOIN объединяются в простые объединения, поэтому оптимизатор выбирает их порядок объединения.

Оптимизатор не выбирает порядок соединения для внешних объединений; он использует порядок, указанный в заявлении.

При выборе порядка соединения оптимизатор принимает во внимание: размер каждой таблицы. Индексы, доступные для каждой таблицы. Полезен ли индекс для таблицы в определенном порядке соединения. Количество строк и страниц, которые нужно отсканировать для каждой таблицы в каждой таблице. объединить заказ

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.