Где против ON во внешнем соединении - PullRequest
1 голос
/ 07 января 2020

Мне интересно, как получить лучшую производительность SQL, когда мы решаем, дублировать ли наши критерии, когда она уже есть в предложении Where.

Мой друг заявил, что это зависит от двигателей БД, но я не да, конечно.

Независимо от механизмов БД, обычно условие в предложении Where должно выполняться сначала перед соединением, но я предполагаю, что это означает внутреннее соединение, а не внешнее соединение. Поскольку некоторые условия могут быть выполнены только ПОСЛЕ внешнего соединения.

Например:

Select a.*, b.* 
From A a
Left outer join B on a.id = b.id 
Where b.id is NULL;

Условие в Where не может быть выполнено до внешнего соединения.

Итак, я предполагаю, что все предложение ON должно быть выполнено в первую очередь перед предложением where, и кажется, что предложение ON будет контролировать размер таблицы B (или таблицы A, если мы используем правое внешнее соединение) перед внешним соединением. Мне кажется, что это не связано с механизмами БД.

И это подняло мой вопрос: когда мы используем внешнее объединение, должны ли мы всегда дублировать наши критерии в предложении ON?

, например (я использую таблица к внешнему соединению с более короткой версией самого себя)

temp_series_installment & series_id> 18940000 vs temp_series_installment :

select sql_no_cache s.*, t.* from temp_series_installment s
left outer join temp_series_installment t on s.series_id = t.series_id and t.series_id > 18940000 and t.incomplete = 1
where t.incomplete = 1;

VS

select sql_no_cache s.*, t.* from temp_series_installment s
left outer join temp_series_installment t on s.series_id = t.series_id and t.series_id > 18940000
where t.incomplete = 1;

Редактировать : где t.incomplete = 1 выполняет лог c из: где t.series_id не нуль, что является внутренним объединением, предложенным Гордоном Линоффом. Но то, что я спрашивал это: если внешнее присоединение к меньшей таблице, это должно было быть быстрее, верно?

Я пытался увидеть, есть ли разница в производительности в mysql:

enter image description here

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

Моя идея из: https://www.ibm.com/support/knowledgecenter/en/SSZLC2_8.0.0/com.ibm.commerce.developer.doc/refs/rsdperformanceworkspaces.htm

Раздел:

Pu sh предикаты в предложении OUTER JOIN, когда это возможно
Дублирование константного условия для разных таблиц, когда это возможно

Ответы [ 2 ]

4 голосов
/ 07 января 2020

Независимо от механизмов БД, как правило, условие в предложении Where должно выполняться сначала до объединения, но я предполагаю, что это означает внутреннее соединение, а не внешнее соединение. Поскольку некоторые условия могут быть выполнены только ПОСЛЕ внешнего соединения.

Это просто неверно. SQL является описательным языком. Он не определяет, как выполняется запрос. Он только указывает, как выглядит результирующий набор. Компилятор / оптимизатор SQL определяет фактические этапы обработки для удовлетворения требований, описанных в запросе.

С точки зрения семантики, предложение FROM является первым предложением, которое «оценивается». Следовательно, FROM логически обрабатывается перед предложением WHERE.

Остальная часть вашего вопроса также ошибочна. Логика сравнения c в предложении where, например:

from s left join
     t
    on s.series_id = t.series_id and t.series_id > 18940000
where t.incomplete = 1

, превращает внешнее соединение во внутреннее соединение. Следовательно, логика c отличается от того, что, по вашему мнению, происходит.

3 голосов
/ 07 января 2020

Как отметил Гордон Линдольф, это неправда, Ваш друг совершенно неправ.

Я хочу просто добавить разработчиков, которые хотели бы думать SQL так, как они думают, что их язык торговли (C ++, VB, * 1031) *), но это процедурные / императивные языки. Когда вы кодируете SQL, вы находитесь в другой парадигме. Вы просто описываете функцию, которая будет применена к набору данных.

Давайте возьмем ваш собственный пример:

Select a.*, b.* 
From A a
Left outer join B on a.id = b.id 
Where b.id is NULL;

Если a.Id и b.Id не являются пустыми столбцами.

Это семантически равно

Select a.*, null, ..., null
From A a
where not exists (select * from B b where b.Id = a.Id)

Теперь попробуйте запустить их для запросов и профиля. В большинстве СУБД можно ожидать, что оба запроса будут выполняться одинаково.

Это происходит потому, что механизм решает, как реализовать вашу "функцию" над набором данных.

Обратите внимание, что приведенный выше пример эквивалент в множестве математики:

Дайте мне множество A минус пересечение между A и B.

Двигатели могут решить, как реализовать ваш запрос, потому что у них есть некоторые трюки под рукавом. Он имеет метрики о ваших таблицах, индексах и т. Д. c и может использовать его, например, для «объединения» в другом порядке, в котором вы его написали.

Сегодня механизмы ИМХО действительно хороши в поиске лучший способ реализовать описанную вами функцию и редко нуждается в подсказках к запросу. Конечно, вы можете закончить описание своей функции слишком сложным образом, что повлияет на то, как движки решат ее запустить. Искусство лучшего описания функций, наборов и индексов управления - это то, что мы называем настройкой запросов.

...