Перейти к основному содержимому

Исполнитель

Исполнитель берет план, созданный планировщиком/оптимизатором, и рекурсивно обрабатывает его, чтобы извлечь требуемый набор строк. По сути, это механизм конвейера «спрос-выбор». Каждый раз, когда вызывается узел плана, он должен доставить еще один ряд или сообщить, что он закончил доставку рядов.

Чтобы привести конкретный пример, предположим, что верхний узел - это узел MergeJoin. Прежде чем произойдет слияние, необходимо получить две строки (по одной из каждого подплана). Поэтому исполнитель рекурсивно вызывает себя для обработки подпланов (он начинает с подплана, прикрепленного к lefttree). Новый верхний узел (верхний узел левого подплана) - это, допустим, узел Sort, и снова требуется рекурсия для получения входной строки. Дочерним узлом Sort может быть узел SeqScan, представляющий фактическое чтение таблицы. Выполнение этого узла заставляет исполнителя получить строку из таблицы и вернуть ее вызывающему узлу. Узел Sort будет неоднократно обращаться к своему дочернему узлу, чтобы получить все строки, подлежащие сортировке. Когда входные данные исчерпаны (на это указывает то, что дочерний узел возвращает NULL вместо строки), код Sort выполняет сортировку и, наконец, может вернуть первую выходную строку, а именно первую строку в отсортированном порядке. Оставшиеся строки он сохраняет, чтобы впоследствии выдать их в отсортированном порядке в ответ на последующие запросы.

Узел MergeJoin аналогичным образом запрашивает первую строку из своего правого подплана. Затем он сравнивает эти две строки, чтобы выяснить, можно ли их объединить; если да, то он возвращает вызывающему его узлу строку объединения. При следующем вызове или сразу, если он не может соединить текущую пару входов, он переходит к следующей строке одной или другой таблицы (в зависимости от того, как прошло сравнение) и снова проверяет совпадение. В конце концов, один или другой подплан исчерпывается, и узел MergeJoin возвращает NULL, чтобы указать, что больше не может быть сформировано ни одной строки соединения.

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

Механизм исполнителя используется для оценки всех пяти основных типов запросов SQL: SELECT, INSERT, UPDATE, DELETE и MERGE. Для SELECT код исполнителя верхнего уровня должен только отправить клиенту каждую строку, возвращенную деревом плана запроса. INSERT ... SELECT, UPDATE, DELETE и MERGE - это фактически SELECT в специальном узле плана верхнего уровня под названием ModifyTable.

INSERT ... SELECT передает строки в ModifyTable для вставки. Для UPDATE планировщик организует так, чтобы каждая вычисленная строка включала все обновленные значения столбцов плюс TID (идентификатор кортежа или строки) исходной целевой строки; эти данные передаются узлу ModifyTable, который использует информацию для создания новой обновленной строки и пометки старой строки как удаленной. Для DELETE единственным столбцом, который фактически возвращается планом, является TID, а узел ModifyTable просто использует TID для посещения каждой целевой строки и пометки ее удаления. Для MERGE планировщик объединяет исходные и целевые отношения и включает все значения столбцов, требуемые любым из WHEN-предложений, плюс TID целевой строки; эти данные передаются в узел ModifyTable, который использует информацию для определения того, какое WHEN-предложение следует выполнить, а затем вставляет, обновляет или удаляет целевую строку, в зависимости от необходимости.

Простая команда INSERT ... VALUES создает тривиальное дерево планов, состоящее из одного результата Result узел, который вычисляет только одну строку результата, передавая ее ModifyTable для выполнения вставки.