Выбрать главу

LIST_PRICE

FROM PERIODICALS

WHERE ...

ORDER BY 2;

Условия поиска и упорядочивания

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

Допустимо только одно предложение упорядочения, оно должно следовать после всех поднаборов. Синтаксис ORDER BY номер (т. е. упорядочение по номеру столбца) требуется для упорядочения объединяемых наборов.

Реентерабельные запросы UNION

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

SELECT

ID,

TITLE,

CAST ('UNDER $20' AS VARCHAR(IO)) AS RANGE,

CAST (AUTHOR_LAST_NAME || ', ' || AUTHOR_FIRST_NAMES AS VARCHAR (50) )

AS AUTHOR,

EDITION,

LIST_PRICE

FROM CURRENT_TITLES CT1

WHERE LIST_PRICE < 20.00

UNION SELECT

ID,

TITLE,

CAST ('UNDER $40' AS VARCHAR(IO),

CAST (AUTHOR_LAST_NAME || ', ' || AUTHOR_FIRST_NAMES AS VARCHAR(50) ) ,

EDITION,

LIST_PRICE

FROM CURRENT_IITLES CT2

WHERE LIST_PRICE >= 20.00 AND LIST_PRICE < 40.00

UNION SELECT

ID,

TITLE,

CAST ('$40 PLUS' AS VARCHAR(IO) ) ,

CAST (AUTHOR_LAST_NAME || ', ' || AUTHOR_FIRST_NAMES AS VARCHAR(50) ) ,

EDITION,

LIST_PRICE

FROM CURRENT_TITLES CT3

WHERE LIST PRICE >= 40.00;

UNION ALL

Если в процессе создания объединенного набора были сформированы дублированные строки, то поведение по умолчанию - исключение из набора дублированных строк. Для включения дубликатов используйте UNION ALL вместо UNION.

Темы оптимизации: планы запросов и оптимизатор

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

Планы и оптимизатор запросов Firebird

Для выполнения оператора SELECT или условия поиска сервер Firebird преобразует оператор в набор внутренних алгоритмов, называемых оптимизированным запросом. Каждый раз, когда оператор подготавливается для выполнения, оптимизатор вычисляет план поиска.

План

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

План создается в соответствии с наличием доступных индексов, с тем способом, каким индексы или потоки соединяются или сливаются, а также с методом поиска (методом доступа).

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

Выражения плана

Для элементов плана в SQL Firebird применяет такой же синтаксис, какой он использует для передачи серверу. Понимание сгенерированных оптимизатором планов может быть очень полезным как для предвидения, каким образом оптимизатор будет решать конкретную задачу, так и в качестве основы для написания пользовательских планов.

Синтаксис выражений плана

Шаблон синтаксиса для фразы PLAN:

<спецификация-запроса> PLAN <выражение-плана>

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

Символы

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

plan-expression := [join-type] (plan-item-list)

join-type := [JOIN] | [SORT] [MERGE]

plan-item-list := plan-item | plan-item, plan-item-list

plan-item := table-identifier access-type | plan_expression

table-identifier := { table-identifier | alias-name } [table-identifier]

access-type := { NATURAL | INDEX (index-list) | ORDER index-name }

index-list := index-name | index-name, index-list

Элементы

Тип соединения (join-type) может быть JOIN или MERGE.

* Тип соединения по умолчанию JOIN (т. е. соединение двух потоков с использованием индекса правого потока для поиска соответствующих ключей в левом потоке).

* MERGE выбирается, если нет используемых индексов. В этом случае два потока сохраняются в соответствующем порядке, а затем сливаются. В пользовательских планах скорость поиска будет увеличена при задании такого типа соединения, когда нет доступных индексов.

Идентификатор таблицы (table-identifier) задает поток. Он должен быть именем таблицы базы данных или алиасом. Если одна и та же таблица будет использована более одного раза, для нее должен быть указан алиас для каждого использования. Алиас должен следовать после имени таблицы при ее первом упоминании. Для спецификации базовых таблиц в просмотре синтаксис предоставляет возможность давать таблицам множество идентификаторов. Планы для просмотров обсуждаются в главе 24.

Тип доступа (access-type) должен быть одним из следующих:

* NATURAL - доступ к строкам осуществляется последовательно, без какого-либо особого порядка. Это тип доступа по умолчанию, он может быть опущен, тем не менее разумно включить его в пользовательский план для документирования;

* INDEX - позволяет указать один или более индексов для вычисления предикатов и проверки условий соединения в запросе;

* ORDER- указывает, что результат запроса должен быть отсортирован (упорядочен) по самому левому потоку с использованием индекса.

Элемент плана (plan-item) включает в себя план доступа, а также идентификатор таблицы или ее алиас.

Оптимизатор

Если вы не очень хорошо знакомы с планами запросов, вы, вероятно, будете удивлены, как весь этот синтаксис может транслироваться в план. Чуть позже синтаксис станет более осмысленным, когда мы посмотрим на некоторые планы, сгенерированные оптимизатором. Тем не менее в настоящий момент будет полезным посмотреть, как оптимизатор использует "материал" для его операций: соединения и условия поиска, требуемые в операторе, потоки, лежащие в основе спецификации запроса, и доступные индексы.

Факторы в оценке преобразований (вычислений)

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