Spec-Zone .ru
спецификации, руководства, описания, API
|
Табличные выражения в 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
Общие правила для того, чтобы проверить, отклоняется ли условие нулем для работы внешнего объединения, просты. Условие отклоняется нулем в следующих случаях:
Если это имеет форму A IS NOT NULL
, где A
атрибут любой из внутренних таблиц
Если это - предикат, содержащий ссылку на внутреннюю таблицу, которая оценивает к
UNKNOWN
когда один из его параметров NULL
Если это - соединение, содержащее отклоненное нулем условие как соединенное
Если это - дизъюнкция отклоненных нулем условий
Условие может быть отклонено нулем для одной работы внешнего объединения в запросе и не отклонено нулем для другого. В запросе:
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