Spec-Zone .ru
спецификации, руководства, описания, API

8.13.10. Упрощение Внешнего объединения

Табличные выражения в FROM пункт запроса упрощается во многих случаях.

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

(T1, ...) RIGHT JOIN (T2,...) ON P(T1,...,T2,...) =(T2, ...) LEFT JOIN (T1,...) ON P(T1,...,T2,...)

Все выражения внутреннего объединения формы T1 INNER JOIN T2 ON P(T1,T2) заменяются списком T1,T2, P(T1,T2) будучи присоединенным как соединенное к WHERE условие (или к условию объединения соединения встраивания, если есть кто-либо).

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

Предположите, что у нас есть запрос формы:

SELECT * T1 LEFT JOIN T2 ON P1(T1,T2)  WHERE P(T1,T2) AND R(T2)

с R(T2) сужение значительно число соответствия строк от таблицы T2. Если бы мы выполнили запрос, как это, то у оптимизатора не было бы никакого другого выбора кроме того к таблице доступа T1 перед таблицей T2 это может привести к очень неэффективному плану выполнения.

К счастью, MySQL преобразовывает такой запрос в запрос без работы внешнего объединения если WHERE условие отклоняется нулем. Условие вызывают отклоненное нулем для работы внешнего объединения, если оно оценивает к FALSE или к UNKNOWN для любого NULL- дополненная строка создается для работы.

Таким образом, для этого внешнего объединения:

T1 LEFT JOIN T2 ON T1.A=T2.A

Условия, такие как они отклоняются нулем:

T2.B IS NOT NULL,T2.B > 3,T2.C <= T1.C,T2.B < 2 OR T2.C > 1

Условия, такие как они не отклоняются нулем:

T2.B IS NULL,T1.B < 3 OR T2.B IS NOT NULL,T1.B < 3 OR T2.B > 3

Общие правила для того, чтобы проверить, отклоняется ли условие нулем для работы внешнего объединения, просты. Условие отклоняется нулем в следующих случаях:

Условие может быть отклонено нулем для одной работы внешнего объединения в запросе и не отклонено нулем для другого. В запросе:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 LEFT JOIN T3 ON T3.B=T1.B  WHERE T3.C > 0

WHERE условие отклоняется нулем для второй работы внешнего объединения, но не отклоняется нулем для первого.

Если WHERE условие отклоняется нулем для работы внешнего объединения в запросе, работа внешнего объединения заменяется работой внутреннего объединения.

Например, предыдущий запрос заменяется запросом:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 INNER JOIN T3 ON T3.B=T1.B  WHERE T3.C > 0

Для исходного запроса оптимизатор оценил бы планы, совместимые только с одним порядком доступа T1,T2,T3. Для запроса замены это дополнительно рассматривает последовательность доступа T3,T1,T2.

Преобразование одной работы внешнего объединения может инициировать преобразование другого. Таким образом, запрос:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 LEFT JOIN T3 ON T3.B=T2.B  WHERE T3.C > 0

будет сначала преобразован в запрос:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A                 INNER JOIN T3 ON T3.B=T2.B  WHERE T3.C > 0

который эквивалентен запросу:

SELECT * FROM (T1 LEFT JOIN T2 ON T2.A=T1.A), T3  WHERE T3.C > 0 AND T3.B=T2.B

Теперь остающаяся работа внешнего объединения может быть заменена внутренним объединением, также, потому что условие T3.B=T2.B отклоняется нулем и мы получаем запрос без внешних объединений вообще:

SELECT * FROM (T1 INNER JOIN T2 ON T2.A=T1.A), T3  WHERE T3.C > 0 AND T3.B=T2.B

Иногда мы преуспеваем в том, чтобы заменить встроенную работу внешнего объединения, но не можем преобразовать внешнее объединение встраивания. Следующий запрос:

SELECT * FROM T1 LEFT JOIN              (T2 LEFT JOIN T3 ON T3.B=T2.B)              ON T2.A=T1.A  WHERE T3.C > 0

преобразовывается в:

SELECT * FROM T1 LEFT JOIN              (T2 INNER JOIN T3 ON T3.B=T2.B)              ON T2.A=T1.A  WHERE T3.C > 0,

Это может быть переписано только к форме, все еще содержащей работу внешнего объединения встраивания:

SELECT * FROM T1 LEFT JOIN              (T2,T3)              ON (T2.A=T1.A AND T3.B=T2.B)  WHERE T3.C > 0.

Пытаясь преобразовать встроенную работу внешнего объединения в запросе, мы должны принять во внимание условие объединения для внешнего объединения встраивания вместе с WHERE условие. В запросе:

SELECT * FROM T1 LEFT JOIN              (T2 LEFT JOIN T3 ON T3.B=T2.B)              ON T2.A=T1.A AND T3.C=T1.C  WHERE T3.D > 0 OR T1.D > 0

WHERE условие не отклоняется нулем для встроенного внешнего объединения, но условия объединения внешнего объединения встраивания T2.A=T1.A AND T3.C=T1.C отклоняется нулем. Таким образом, запрос может быть преобразован в:

SELECT * FROM T1 LEFT JOIN              (T2, T3)              ON T2.A=T1.A AND T3.C=T1.C AND T3.B=T2.BWHERE T3.D > 0 OR T1.D > 0