37.1. Дерево запроса
Чтобы понять, как работает система правил, нужно знать, когда она вызывается, что принимает на вход и какой результат выдаёт.
Система правил внедрена между анализатором запросов и планировщиком. Она принимает разобранный запрос, одно дерево запроса, и определённые пользователем правила перезаписи, тоже представленные деревьями с некоторой дополнительной информацией, и создаёт некоторое количество деревьев запросов в результате. Таким образом, на входе и выходе этой системы оказывается то, что может сформировать анализатор запросов, и как следствие, всё, с чем работает эта система, представимо в виде операторов SQL.
Так что же такое дерево запроса? Это внутреннее представление оператора SQL, в котором все образующие его части хранятся отдельно. Эти деревья можно увидеть в журнале сервера, если установить параметры конфигурации debug_print_parse
, debug_print_rewritten
или debug_print_plan
. Действия правил также хранятся в виде деревьев запросов, в системном каталоге pg_rewrite
. Они не форматируются как при выводе в журнал, но содержат точно такую же информацию.
Для прочтения неформатированного дерева требуется некоторый навык. Но так как представления дерева запросов в виде SQL достаточно, чтобы понять систему правил, в этой главе не будет рассказываться, как их читать.
Читая SQL-представления деревьев запросов в этой главе, необходимо понимать, на какие части разбивается оператор, когда он преобразуется в структуру дерева запроса. Дерево запроса состоит из следующих частей:
- тип команды
Это простое значение, говорящее, какая команда (
SELECT
,INSERT
,UPDATE
илиDELETE
) сгенерировала дерево запросов.- список отношений
Список отношений представляет собой массив отношений, используемых в запросе. В запросе
SELECT
он включает отношения, указанные после ключевого словаFROM
.Каждый элемент списка отношений представляет таблицу или представление и говорит, с каким именем они упоминаются в других частях запроса. В дереве запросов записываются номера элементов списка отношений, а не их имена, поэтому для него неактуальна проблема дублирования имён, как для оператора SQL. Такая проблема может возникнуть при объединении списков отношений, образованных разными правилами. В этой главе данная ситуация рассматриваться не будет.
- результирующее отношение
Индекс в списке отношений, указывающий на отношение, которое будет получать результаты запроса.
В запросах
SELECT
результирующее отношение отсутствует. (Особый случайSELECT INTO
практически равнозначенCREATE TABLE
с последующимINSERT ... SELECT
и здесь отдельно не рассматривается.)Для команд
INSERT
,UPDATE
иDELETE
результирующим отношением будет таблица (или представление!), в которой будут происходить изменения.- выходной список
Выходной список — это список выражений, определяющих результат запроса. В случае
SELECT
, это выражения, которые образуют окончательный набор выходных данных. Они соответствуют выражениям, записанным между ключевыми словамиSELECT
иFROM
. (Указание*
— это просто краткое обозначение имён всех столбцов отношения. Анализатор разворачивает его в список отдельных столбцов, так что система правил никогда не видит его.)Командам
DELETE
не нужен обычный выходной список, так как они не выдают никакие результаты. Вместо этого планировщик добавляет в пустой выходной список специальную запись CTID, чтобы исполнитель мог найти удаляемую строку. (CTID добавляется, когда результирующее отношение — обычная таблица. Если это представление, планировщиком добавляется переменная, содержащая всю строку, как рассказывается в Подразделе 37.2.4.)Для команд
INSERT
выходной список описывает новые строки, которые должны попасть в результирующее отношение. Он включает выражения в предложенииVALUES
или предложенииSELECT
вINSERT ... SELECT
. На первом этапе процесс перезаписи добавляет элементы выходного списка для столбцов, которым ничего не присвоила исходная команда, но имеющих значения по умолчанию. Все остальные столбцы (без заданного значения и значения по умолчанию) планировщик заполняет константой NULL.Для команд
UPDATE
выходной список описывает новые строки, которые должны заменить старые. В системе правил он содержит только выражения из частиSET столбец = выражение
. Для пропущенных столбцов планировщик вставляет выражения, копирующие значения из старой строки в новую. Так же, как и с командойDELETE
, при этом добавляется CTID или переменная со всей строкой, чтобы исполнитель мог найти изменяемую старую строку.Каждая запись в выходном списке содержит выражение, которое может быть константой, переменной, указывающей на столбец отношения в таблице отношений, параметром или деревом выражений, образованным из констант, переменных, операторов, вызовов функций и т. д.
- условие фильтра
Условие фильтра запроса — это выражение, во многом похожее на те, что содержатся в выходном списке. Результат этого выражения — логический, он говорит, должна ли выполняться операция (
INSERT
,UPDATE
,DELETE
илиSELECT
) для данной строки в результате. Оно соответствует предложениюWHERE
SQL-оператора.- дерево соединения
Дерево соединения запроса показывает структуру предложения
FROM
. Для простых запросов видаSELECT ... FROM a, b, c
, дерево соединения — это просто список элементовFROM
, так как они могут соединяться в любом порядке. Но с выражениямиJOIN
, особенно с внешними соединениями, приходится соединять отношения именно в заданном порядке. В этом случае дерево соединения отражает структуру выраженийJOIN
. Ограничения, связанные с конкретными предложениямиJOIN
(из выраженийON
илиUSING
), тоже сохраняются в виде условных выражений, добавленных к соответствующим узлам дерева соединения. Как оказалось, выражениеWHERE
верхнего уровня тоже удобно хранить как условие, добавленное к элементу верхнего уровня дерева соединения. Поэтому в дереве соединения на самом деле представляются оба предложения оператораSELECT
—FROM
иWHERE
.- другие
Другие части дерева запроса, например, предложение
ORDER BY
, в данном контексте не представляют интереса. Система правил выполняет в них некоторые подстановки, применяя правила, но это не имеет непосредственного отношения к основам системы правил.