50.6. Исполнитель#

50.6. Исполнитель

50.6. Исполнитель

Исполнитель (executor) берет план, созданный планировщиком/оптимизатором, и рекурсивно обрабатывает его, чтобы извлечь необходимый набор строк. Это, по сути, механизм поточной передачи данных по требованию. Каждый раз, когда вызывается узел плана, он должен доставить еще одну строку или сообщить, что доставка строк завершена.

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

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