Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Тоу Д. -> "Настройка SQL. Для профессионалов" -> 51

Настройка SQL. Для профессионалов - Тоу Д.

Тоу Д. Настройка SQL. Для профессионалов — СПб.: Питер, 2004. — 333 c.
ISBN 5-94723-959-0
Скачать (прямая ссылка): nastroykasqldlyaprof2004.djvu
Предыдущая << 1 .. 45 46 47 48 49 50 < 51 > 52 53 54 55 56 57 .. 161 >> Следующая


Запрещение соединения в неправильном порядке

Задание соединений в желаемом порядке с применением описанных способов предотвращения использования неправильных индексов также поможет запретить проводить соединения в нежелательном порядке. Что следует делать, если вы хотите, чтобы база данных создала некое соединение в определенном порядке не слишком рано в плане выполнения? Нельзя запрещать использовать индекс, поскольку однажды он может понадобиться, просто не очень скоро. Рассмотрим два соединения, в которых вы хотите, чтобы запрос начал со считывания из Tl, затем соединил результат с Т2, и затем с ТЗ:

... AND Tl.Key2_ID=T2.Key2_ID AND Tl.Key3_ID=T3.Key3_ID ...

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

... AND Tl.Key2_ID=T2.Key2_ID

AND Tl.Key3_ID+0*T2.Key2_ID=T3.Key3_ID ...

Мы знаем, что второй вариант логически эквивалентен первому. Однако база данных находит в левой части второго соединения выражение, которое зависит от Tl и TZ (не понимая, что значения из TZ не могут изменить результат), поэтому она не будет пытаться выполнить соединение с ТЗ до соединения с Т2.
Универсальные техники управления планами

103

Если необходимо, можно подобным образом связать все соединения, чтобы полностью контролировать порядок соединения. Для каждого соединения, следующего за первым, добавьте к выражению соединения логически несущественный компонент, который ссылается на один из столбцов, добавленных в предыдущем соединении. Например, если вы хотите, чтобы обращения к таблицам с Tl по Т5 шли по порядку, можно использовать следующий код. Обратите внимание, что в условии соединения для таблицы ТЗ используется выражение 0*Т2. Key2_ID, чтобы сначала было выполнено соединение с Т2. Подобным образом в условии соединения для таблицы Т4 используется 0*T3. Key3_ID, чтобы сначала было выполнено соединение с ТЗ.

... AND Tl.Key2_ID=T2.Key2_ID AND Tl.Key3_ID+0*T2.Key2_ID = T3.Key3_ID AND Tl.Key4_ID+0*T3.Key3_ID = T4.Key4_ID AND Tl.Key4_I0+0*T4.Key4_lD = T5.Key5_ID ...

Я воспользуюсь этим методом на конкретном примере. Возьмем из главы 3 следующий SQL-код.

SELECT E.First_Name. E.Last_Name. Е.Sal агу. LE.Description.

M.First_Name. M.Last_Name. LM.Description FROM Locations LE. Locations LM. Employees M. Employees E WHERE E.Last_Name = 'Johnson'

AND E.Manager_ID = M.Employee_ID AND E.LocationID = LE.Location_ID AND M.Location_ID = LM.Location_ID AND LE.Description = 'Dallas'

Предположим, что у нас есть план выполнения, который начинает с индекса по фамилии сотрудников, но вы обнаружили, что соединение с местоположением сотрудников (псевдоним LE), чтобы отбросить всех сотрудников, не находящихся в Далласе (Dal I as), к сожалению, происходит в последнюю очередь, после остальных соединений (с M и LM). Необходимо присоединить LE сразу же после Е, чтобы минимизировать количество строк, которое потребуется соединить с остальными двумя таблицами. Если начать с Е, то сразу же выполнить соединение с LM невозможно, поэтому если вы запретите соединение с M перед LE, то должны получить желаемый порядок соединения. Как это сделать:

SELECT E.First_Name. E.Last_Name. Е.Sal агу. LE.Description.

M.FirstName. M.Last_Name. LM. Descri pti on FRDM Locations LE. Locations LM. Employees M. Employees E WHERE E.Last_Name = 'Johnson'

AND E.Manager_ID + 0*LE.Location_ID=M.Employee_ID AND E.Location_ID = LE.Location_ID AND M.Location_ID = LM.Location_ID AND LE.Description = 'Dallas'

Смысл в том, что я сделал соединение с M зависящим от значения из LE. Выражение 0*LE.Location_ID заставляет оптимизатор выполнить соединение с LE до М. Благодаря умножению на ноль добавленное выражение не влияет на результаты, возвращенные запросом.

Выбор порядка выполнения для внешних запросов и подзапросов

Большинство запросов с подзапросами могут логически начинаться с внешнего запроса или подзапроса. В зависимости от селективности условия подзапроса лю-
104

4. Управление планами выполнения

бой вариант может быть лучшим. Обычно проблема выбора встает для запросов с условиями EXISTS и IN. Всегда можно преобразовать условие EXISTS для коррелированного подзапроса в эквивалентное условие IN для не коррелированного подзапроса и наоборот. Например, такой запрос:

SELECT ...

FROM Departments D

WHERE EXISTS (SELECT NULL FROM Employees E

WHERE E.Department_ID=D.Department_ID)

можно преобразовать в следующий код:

SELECT ...

FROM Departments D

WHERE D.Department_ID IN (SELECT E. Department^ D FROM Employees E)

Первая форма подразумевает, что база данных начинает с внешнего запроса и переходит к подзапросу. Для каждой строки, возвращенной внешним запросом, база данных выполняет соединение в подзапросе. Вторая форма подразумевает, что выполнение начинается со списка различных отделов, в которых существуют сотрудники, найденные подзапросом, и переходит от этого списка к соответствующему списку отделов во внешнем запросе. Иногда база данных сама использует подразумеваемый порядок соединения, хотя некоторые базы данных могут неявно выполнять преобразование, если оптимизатор обнаружит, что альтернативный порядок лучше. Чтобы сделать SQL-код более удобочитаемым и заставить его хорошо работать вне зависимости от того, может ли ваша база данных преобразовывать формы, используйте ту форму записи запроса, которая явно указывает желаемый порядок установки соединений. Чтобы этот порядок выполнялся, даже если база данных может провести преобразование, используйте те же техники выбора направления соединения, которые были описаны в разделе «Запрещение соединения в неправильном порядке». Так, условие EXISTS, которое заставляет внешний запрос выполняться первым, будет выглядеть так:
Предыдущая << 1 .. 45 46 47 48 49 50 < 51 > 52 53 54 55 56 57 .. 161 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100