Смешивание левого и правого соединений? Зачем? - PullRequest
3 голосов
/ 22 июля 2009

Выполнение рефакторинга в устаревшем коде, который я нашел в проекте. Это для MSSQL. Дело в том, что я не могу понять, почему мы используем смешанные соединения слева и справа и объединяем некоторые условия соединения.

У меня такой вопрос: не создает ли это неявные внутренние объединения в одних местах и ​​неявные полные объединения в других?

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

Кроме того, мы конвертируем все это для работы и с базами данных oracle, поэтому, может быть, есть некоторые правила оптимизации, которые по-разному работают с Ora?

Например, вот часть ОТ одного из запросов:

        FROM    Table1
        RIGHT OUTER JOIN Table2
            ON Table1.T2FK = Table2.T2PK
        LEFT OUTER JOIN Table3
        RIGHT OUTER JOIN Table4
        LEFT OUTER JOIN Table5
            ON Table4.T3FK = Table5.T3FK
               AND Table4.T2FK = Table5.T2FK
        LEFT OUTER JOIN Table6
        RIGHT OUTER JOIN Table7
            ON Table6.T6PK = Table7.T6FK
        LEFT OUTER JOIN Table8
        RIGHT OUTER JOIN Table9
            ON Table8.T8PK= Table9.T8FK
            ON Table7.T9FK= Table9.T9PK
            ON Table4.T7FK= Table7.T7PK
            ON Table3.T3PK= Table4.T3PK
        RIGHT OUTER JOIN ( SELECT   *
                           FROM     TableA
                           WHERE    ( TableA.PK = @PK )
                                    AND ( TableA.Date BETWEEN @StartDate
                                                                    AND     @EndDate )
                         ) Table10
            ON Table4.T4PK= Table10.T4FK
            ON Table2.T2PK = Table4.T2PK

Ответы [ 7 ]

4 голосов
/ 22 июля 2009

Одна вещь, которую я хотел бы сделать, это убедиться, что вы знаете, каких результатов вы ожидаете, прежде чем возиться с этим. Не хотел бы это "исправить" и получить другие результаты. Хотя, если честно, с плохо спроектированным запросом, я не уверен, что вы действительно получаете правильные результаты прямо сейчас.

Для меня это выглядит как нечто, что кто-то делал со временем, может быть, даже первоначально, начиная с внутренних объединений, понимая, что они не будут работать, и переходя на внешние объединения, но не желая беспокоиться об изменении порядка обращения к таблицам в запросе. 1003 *

Особое беспокойство для меня в целях обслуживания заключается в том, чтобы поместить предложения ON рядом с таблицами, к которым вы присоединяетесь, а также преобразовать все объединения в левые объединения, а не смешивать правое и левое соединения. Наличие предложения ON для таблицы 4 и таблицы 3 рядом с таблицей 9 не имеет никакого смысла для меня и должно привести к путанице относительно того, что запрос должен фактически возвращать. Вам также может понадобиться изменить порядок объединений, чтобы преобразовать их во все оставленные объединения. Лично я предпочитаю начать с основной таблицы, к которой присоединятся другие (которая выглядит как table2), а затем оттуда работать по пищевой цепи.

1 голос
/ 22 июля 2009

LEFT и RIGHT объединение - чистый синтаксический сахар.

Любой LEFT JOIN может быть преобразован в RIGHT JOIN простым переключением наборов.

Предварительно 9i Oracle использовал эту конструкцию:

WHERE  table1.col(+) = table2.col

, (+) здесь обозначает обнуляемый столбец, а объединения LEFT и RIGHT можно эмулировать простым переключением:

WHERE  table1.col = table2.col(+)

В MySQL нет FULL OUTER JOIN, и его нужно эмулировать.

Обычно это делается так:

SELECT  *
FROM    table1
LEFT JOIN
        table2
ON      table1.col = table2.col
UNION ALL
SELECT  *
FROM    table1
RIGHT JOIN
        table2
ON      table1.col = table2.col
WHERE   table1.col IS NULL

, и удобнее скопировать JOIN и заменить LEFT на RIGHT, чем поменять местами таблицы.

Обратите внимание, что в SQL Server планах Hash Left Semi Join и Hash Right Semi Join являются разными операторами.

Для запроса, подобного следующему:

SELECT  *
FROM    table1
WHERE   table1.col IN
        (
        SELECT  col
        FROM    table2
        )

, Hash Match (Left Semi Join) хэширует table1 и удаляет сопоставленные элементы из хеш-таблицы во время выполнения (чтобы они не могли совпадать более одного раза).

Hash Match (Right Semi Join) хэширует table2 и удаляет дублирующиеся элементы из хеш-таблицы при ее создании.

1 голос
/ 22 июля 2009

Вероятно, он может быть преобразован для использования всех левых соединений: я буду искать и перемещать правую таблицу в каждом ПРАВО, чтобы она была выше всех существующих ЛЕВЫХ, тогда вы могли бы превратите каждое ПРАВОЕ соединение в ЛЕВОЕ соединение. Я не уверен, что вы получите какие-либо полные объединения за кулисами - если запрос выглядит так, это может быть причудой этого конкретного запроса, а не «правилом» SQL Server: этот запрос, который вы предоставили, делает кажется, что все путается довольно запутанно.

Что касается оптимизации Oracle - это, безусловно, возможно. У меня нет опыта работы с Oracle, но, говоря с другом, который хорошо разбирается в этой области, Oracle (понятия не имеет, какая версия) суетился относительно порядка предикатов. Например, в SQL Server вы можете написать свое предложение way, чтобы столбцы располагались в любом порядке, и индексы привыкли, но в Oracle вам придется указывать столбцы в том порядке, в котором они появляются в индексе, чтобы добиться максимальной производительности. с указателем. Как уже говорилось - не знаю, так ли это с более новыми Oracle, но было с более старыми (очевидно).

Я не могу сказать, объясняет ли это эту конкретную конструкцию. Это мог бы быть просто неоптимальный код, если бы он менялся годами, и он просит об очистке.

0 голосов
/ 11 февраля 2013

Чтобы ответить на другую часть этого вопроса, на которую еще не ответили, причина, по которой этот запрос так странно отформатирован, заключается в том, что он, вероятно, построен с использованием конструктора запросов в SQL Management Studio. Выдача - это объединенные предложения ON, которые происходят через много строк после упоминания таблицы. По сути, таблицы добавляются в окне запросов на сборку, и порядок сохраняется, даже если при таком соединении вещи будут способствовать перемещению таблицы, так сказать, и сохранению всех объединений в определенном направлении.

0 голосов
/ 22 июля 2009

Суть в том, что это очень плохо отформатированный оператор SQL, и его следует переписать. Многие из предложений ON расположены далеко от их операторов JOIN, что, я не уверен, даже является допустимым SQL.

Для ясности я переписал бы запрос, используя все ВЛЕВОЕ СОЕДИНЕНИЕ (а не ВПРАВО), и поместил бы операторы использования под их соответствующими предложениями JOIN. Иначе, это немного крушение поезда, и это запутывает цель запроса, делая ошибки во время будущих модификаций более вероятными.

не создает ли это неявное внутреннее включается в некоторых местах и ​​неявно полный присоединяется к другим?

Возможно, вы предполагаете, что, поскольку вы не видите предложение ON для некоторых объединений, например, RIGHT OUTER JOIN Table4, но оно расположено внизу, ON Table4.T7FK= Table7.T7PK. Я не вижу никаких неявных внутренних объединений, которые могли бы произойти, если бы было предложение WHERE, подобное WHERE Table3.T3PK is not null.

Тот факт, что вы задаете такие вопросы, свидетельствует о непрозрачности запроса.

0 голосов
/ 22 июля 2009

У нас есть LEFT OUTER JOIN s и RIGHT OUTER JOIN s в одном запросе. Как правило, такие запросы являются большими, они выполнялись долгое время, в первую очередь, вероятно, плохо написаны и редко обслуживались. Я предполагаю, что RIGHT OUTER JOIN были введены как средство поддержки запроса, не принимая на себя неизбежный риск при значительном рефакторинге запроса.

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

Единственный раз, когда я сам использую RIGHT OUTER JOIN, это когда при написании нового запроса на основе существующего запроса (нет необходимости заново изобретать колесо), и мне нужно изменить INNER JOIN на OUTER JOIN. Вместо того, чтобы изменить порядок JOIN в предложении FROM, просто чтобы иметь возможность использовать LEFT OUTER JOIN, я бы вместо этого использовал RIGHT OUTER JOIN, и это не беспокоило бы меня. Это довольно редко, хотя. Если бы в исходном запросе было LEFT OUTER JOIN с, то я бы получил комбинацию LEFT - и RIGHT OUTER JOIN с, что опять-таки меня не беспокоит. Но со мной еще ничего не случилось.

Обратите внимание, что для продуктов SQL, таких как ядро ​​базы данных Access, которые не поддерживают FULL OUTER JOIN, одним из обходных путей является UNION a LEFT OUTER JOIN и RIGHT OUTER JOIN в одном запросе.

0 голосов
/ 22 июля 2009

Я могу что-то упустить здесь, но единственная разница между соединениями LEFT и RIGHT заключается в том, в каком порядке были записаны исходные таблицы, и поэтому наличие нескольких LEFT-соединений или нескольких RIGHT-соединений ничем не отличается от наличия микса. Эквивалентность FULL OUTERs может быть достигнута так же легко со всеми LEFT / RIGHT, чем со смесью, n'est pas?

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