Правда ли, что все типы объединений сводятся к внутренним соединениям при наличии проверки pk = fk одной таблицы? - PullRequest
2 голосов
/ 10 июня 2009

Правда ли, что независимо от того, какой тип объединения вы используете, если ваше предложение WHERE проверяет pk = fk одной таблицы, оно становится таким же, как и внутреннее объединение, насколько связан набор результатов? Другими словами, если в вашем sql-запросе есть что-то вроде:

"Выбрать ... из левого соединения B вкл. (...) E, F полное внешнее соединение G вкл. (A.pk = G.fk) ... ГДЕ A.pk = G.fk и A. pk = B.fk и т.д ... "

В приведенном выше запросе A соединен слева с B, тогда как G внешне соединен с A на его fk. Но так как предложение where имеет две проверки, весь запрос сводится к чему-то вроде:

"Выбрать ... из ВНУТРЕННЕГО РЕГИОНА B Вкл. (...) E, F ВНУТРЕННЕГО ВХОДА В G (А.pk = G.fk) ... ГДЕ и т. Д. ..."

Причина запроса этого запроса состоит в том, что у меня есть много объединений декартового типа наряду с предложениями where, которые находятся в pk = одной таблицы fk другой таблицы, которые замедляют запрос. Я думал о замене декартовых произведений либо левыми соединениями в сочетании с сохранением всех положений where, либо всех внутренних соединений.

Ответы [ 3 ]

3 голосов
/ 10 июня 2009

Да, это окольный способ получения внутреннего соединения.

Подумайте о том, как это работает: он вытягивает все из A, затем совпадающие B или нули, затем все G (нули со стороны A / B и G), а затем по существу отфильтровывает все, что имеет нулевую сторону это (ГДЕ предложение). Так что, да, скорее всего, ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

Распространенным источником этой путаницы является то, что это:

SELECT * FROM a INNER JOIN b ON a.id = b.id AND b.something = 'awesome'

эквивалентно:

SELECT * FROM a INNER JOIN b ON a.id = b.id WHERE b.something = 'awesome'

Однако этот же транзитивный подход не работает с полными / внешними объединениями, так как он выполняет объединение, а затем фильтрует (в зависимости, конечно, от фильтров и оптимизатора).

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

Редактировать: Я также должен отметить, что это не сделка с PK / FK, а если вы по существу повторите предложение ON в предложении WHERE, полное / внешнее объединение станет эквивалентным внутреннему объединению.

1 голос
/ 10 июня 2009

Да, если вы ссылаетесь на правую часть левого внешнего соединения в предложении where чем-либо, кроме «где myfield равно нулю», вы создали внутреннее соединение. Это потому, что он отфильтровывает все, что не соответствует этому условию, включая все записи, которые не соответствуют начальной таблице. То же самое с другими не внутренними соединениями. Чтобы обойти это, вы помещаете условие в соединение. Пример (это превращает его во внутреннее соединение):

Select field1, field2 from mytable mt
left join mytable2 mt2 on mt.id = m2.id
where mt1.field1 = 'hello' and mt2.field2 = 'test'

Переписано для сохранения левого соединения:

Select field1, field2 from mytable mt
left join mytable2 mt2 on mt.id = m2.id and mt2.field2 = 'test'
where mt1.field1 = 'hello' 

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

"Выбрать ... из внутреннего соединения B на (A.id = B.a_id), C, D, F, где A.id = F.id" для: "Выбрать ... из внутреннего соединения B на (A.id = B.a_id), C, D ВНУТРЕННЕГО СОЕДИНЕНИЯ F на A.id = F.a_id"

Вы не хотите комбинировать синтаксис, подобный этому; это становится очень трудно поддерживать. Фактически я рекомендую никогда не использовать синтаксис запятых старого стиля, так как он подвержен случайным перекрестным соединениям. Таким образом, в вашем примере я написал бы, чтобы получить набор результатов, который вы в настоящее время получаете (по крайней мере, кто-то из обслуживающих будет знать, что вы добавили перекрестное соединение вместо того, чтобы сделать это случайно):

Select ... From A 
INNER JOIN B on A.id = B.a_id 
INNER JOIN F on A.id = F.a_id
CROSS JOIN C
CROSS JOIN D

Альтернативно, если перекрестное соединение является случайным, код изменится на:

Select ... From A 
INNER JOIN B on A.id = B.a_id
INNER JOIN F on A.id = F.a_id
INNER JOIN C on (fill in the join fields)
INNER JOIN D on (fill in the join fields)
1 голос
/ 10 июня 2009

Да, и вы также можете просто добавить

"Where PK Is Not Null" or 
"Where FK Is Not Null" 

и это также отфильтровывает "лишние" записи с "внешней" стороны соединения ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...