Чтение онлайн

ЖАНРЫ

Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ

Борри Хелен

Шрифт:

SELECT * FROM DEPARTMENT D

JOIN PROJECT P

ON D.MNGR_NO = P. TEAM_LEADER ;

PLAN JOIN (D NATURAL,P INDEX (RDB$FOREIGN13))

Соединение с индексированным предложением ORDER BY

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

SQL> SELECT P.*, E.FULL_NAME FROM PROJECT P JOIN EMPLOYEE E

ON E.EMP_NO = Р. TEAM_LEADER ORDER BY P.PROJ_NAME ;

PLAN JOIN (Р ORDER RDB$11, E INDEX (RDB$PRIMARY7))

Уникальный индекс для EMPLOYEE выбирается по причине неявного условия фильтра в критерии соединения. Запрос сокращает

количество служащих, которые не являются руководителями, а уникальный индекс позволяет исключить сканирование таблицы EMPLOYEE. Выбор индекса фильтрации может также повлиять на необходимость использования навигационного индекса в PROJ_NAME для сортировки [83] .

Оптимизатор выбирает индекс правой стороны, потому что правый поток будет того же размера, что и левый или (потенциально) большего размера. Опять же, оптимизатор не может сказать, что это отношение является отношением один к одному. Столбец PROJ_NAME, задающий порядок выходного набора, имеет уникальный индекс, созданный ограничением UNIQUE, чтобы использовать для сортировки, и оптимизатор выбирает этот индекс. Индекс сортировки появляется в плане первым, указывая серверу на необходимость сортировки левого потока перед тем, как он будет отыскивать соответствие ключа соединения в правом потоке.

83

"Сортировка по индексу" является недоразумением. Предложение ORDER В плане запроса дает указания серверу читать поток вне порядка хранения (то есть с использованием навигационного индекса для поиска строк). Этот метод может работать только с управлением потоком в цикле и создавать предварительно упорядоченный результат. Поскольку ORDER может быть использован только для левого потока в соединении, любое правило, которое влияет на упорядоченность соединения - например, внешнее соединение, которое не дает возможность потоку быть самым левым - будет иметь преимущество.

Соединение равенства при отсутствии доступных индексов

Таблицы в следующем запросе являются неиндексированными копиями таблиц PROJECT и EMPLOYEE (см. сноску 4 ранее в этой главе):

SQL> SELECT PI.*, EL. FULL_NAME FROM PROJECT1 PI JOIN EMPLOYEEL EL ON EL.EMP_NO = PL.TEAM_LEADER ORDER BY PI. PROJ_NAME;

PLAN SORT (MERGE (SORT (EL NATURAL) , SORT (PI NATURAL)))

Потоки с обеих сторон будут сортироваться, а затем сливаться, полученная река снова будет сортироваться, потому что ни один из потоков не имеет требуемого порядка сортировки.

Трехстороннее соединение с индексированными равенствами

Рассмотрим тройное эквисоединение в следующем примере:

SQL> SELECT P.PROJ_NAME, D.DEPARTMENT, PDB. PROJECTED_BUDGET FROM PROJECT P

JOIN PROJ_DEPT_BODGET PDB ON P.PROJ_ID = PDB.PROJ_ID JOIN DEPARTMENT D ON PDB.DEPT_NO = D.DEPT_NO;

PLAN JOIN (D NATURAL, PDB INDEX (RDB$FOREIGN18), P INDEX (RDB$PRIMARY12))

Поскольку доступно множество подходящих индексов, оптимизатор выбирает метод доступа JOIN. Индекс, связывающий поток PDB с таблицей DEPARTMENT, будет использован для выбора потока DEPARTMENT. При обработке результирующей реки и потока PROJECT эквисоединение между первичным ключом таблицы PROJECT и большей по размеру (потенциально) реки дает возможность формировать реку с использованием индекса первичного ключа PROJECT для выборки данных из реки.

Трехстороннее соединение

только с одним индексированным равенством

Для этого примера мы используем неиндексированные копии таблиц PROJECT и EMPLOYEE для демонстрации того, как оптимизатор будет использовать доступный индекс, когда он может применять лучший вариант условий неиндексированного эквисоединения:

SQL> SELECT PI.PROJ_NAME, DL.DEPARTMENT, PDB.PROJECTED_BUDGET FROM PROJECT1 PI

JOIN PROJ_DEPT_BUDGET PDB ON PI . PROJ_ID = PDB.PROJ_ID

JOIN DEPARTMENT1 Dl ON PDB. DEPT_NO = Dl. DEPT_NO;

PLAN MERGE (SORT

(PI NATURAL), SORT (JOIN (Dl NATURAL, PDB INDEX (RDB$FOREIGN18))))

В

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

После этого результирующая река и поток PROJECT сортируются. В завершение (в самом внешнем цикле) два сортированных потока объединяются в один.

Запросы с множеством планов

Когда в запросе задаются подзапросы и объединения, используется несколько операторов SELECT. Оптимизатор конструирует независимый план для каждого оператора SELECT. Возьмем следующий пример:

SELECT

P.PROJ_NAME,

(SELECT E.FULL_NAME FROM EMPLOYEE E

WHERE P.TEAM_LEADER = E.EMP_NO) AS LEADER_NAME

FROM PROJECT P

WHERE P.PRODUCT = 'software'

PLAN (Е INDEX (RDB$PRIMARY7) )

PLAN (Р INDEX (PRODTYPEX))

Первый план выбирает индекс первичного ключа таблицы EMPLOYEE для просмотра кодов TEAM_LEADER в первичной таблице подзапроса. Индекс PRODTYPEX для таблицы PROJECT используется для фильтрации строк в таблице PRODUCT, поскольку первым элементом ключа в этом индексе является столбец PRODUCT.

Интересно то, что если изменить тот же запрос, включив предложение упорядочения, то оптимизатор изменит свой выбор индекса для фильтрации и выберет уникальный индекс по PROJ_NAME для навигации по упорядочиваемому столбцу:

SELECT

P.PROJ_NAME,

(SELECT E.EULL_NAME FROM EMPLOYEE E

WHERE P.TEAM_LEADER = E.EMP_NO) AS LEADER_NAME

FROM PROJECT P

WHERE P.PRODUCT = 'software' ORDER BY 1;

PLAN (E INDEX (RDB$PRIMARY7))

PLAN (P ORDER RDB$11)

Задание вашего собственного плана

Синтаксис выражений, который использует оптимизатор для создания плана и передачи его серверу Firebird доступен в SQL в предложении PLAN. Это позволяет вам определять ваш собственный план, ограничивая оптимизатор в его выборе.

Предложение PLAN может быть задано почти в любом операторе SELECT, включая операторы, используемые в создании просмотров, в хранимых процедурах и подзапросах. Firebird версии 1.5 и выше также допускает предложения PLAN и в триггерах. Множество планов может быть указано независимо для запроса и любого подзапроса. При этом нет требования "все или ничего" - любое предложение плана является необязательным.

Предложение PLAN генерируется для оператора SELECT В хранимой процедуре выбора. Поскольку выходом хранимой процедуры выбора является виртуальный набор, любые условия будут основываться на доступе NATURAL. При этом любой оператор SELECT в хранимой процедуре будет оптимизирован, и для него можно применять пользовательский план.

! ! !

ПРИМЕЧАНИЕ. Конструирование пользовательского плана для оператора SELECT в просмотре создает собственные проблемы для разработчика. Более подробную информацию см. в разд. "Использование планов запросов для просмотров" главы 24.

. ! .

Вы должны задать имена и порядок использования для всех индексов, которые будут использованы.

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

Поделиться с друзьями: