Документация по PostgreSQL 9.4.1 | |||
---|---|---|---|
Пред. | Уровень выше | Глава 53. Написание обёртки сторонних данных | След. |
53.4. Планирование запросов с обёртками сторонних данных
Процедуры в FDW, реализующие функции GetForeignRelSize
, GetForeignPaths
, GetForeignPlan
и PlanForeignModify
должны вписываться в работу планировщика PostgreSQL. Здесь даётся несколько замечаний о том, как это должно происходить.
Для уменьшения объёма выбираемой из сторонней таблицы информации (и как следствие, сокращения стоимости) может использоваться информация, поступающая в root и baserel. Особый интерес представляет поле baserel->baserestrictinfo, так как оно содержит ограничивающие условия (предложения WHERE), по которым можно отфильтровать выбираемые строки. (Сама FDW не обязательно должна применять эти ограничения, так как их может проверить и ядро исполнителя.) Список baserel->reltargetlist позволяет определять, какие именно колонки требуется выбрать; но учтите, что в нём перечисляются только те колонки, которые выдаются узлом плана ForeignScan, но не колонки, которые задействованы в ограничивающих условиях и при этом не выводятся запросом.
Когда функциям планирования FDW требуется сохранять свою информацию, они могут использовать различные частные поля. Вообще, все структуры, которые FDW помещает в закрытые поля, должны выделяться функцией palloc, чтобы они автоматически освобождались при завершении планирования.
Для хранения информации, относящейся к определённой сторонней таблице, функции планирования FDW могут использовать поле baserel->fdw_private, которое может содержать указатель на void. Ядро планировщика никак не касается его, кроме того, что записывает в него NULL при создании узла baserel. Оно полезно для передачи информации из GetForeignRelSize
в GetForeignPaths
и/или из GetForeignPaths
в GetForeignPlan
и позволяет избежать повторных вычислений.
GetForeignPaths
может обозначить свойства различных путей доступа, сохранив частную информацию в поле fdw_private узлов ForeignPath. Это поле fdw_private объявлено как указатель на список (List), но в принципе может содержать всё, что угодно, так как ядро планировщика его не касается. Однако лучше поместить в него данные, которые сможет представить функция nodeToString
, для применения средств отладки, имеющихся на сервере.
GetForeignPlan
может изучить поле fdw_private выбранного узла ForeignPath и сформировать списки fdw_exprs и fdw_private, которые будут помещены в узел ForeignScan, где они будут находиться во время выполнения запроса. Оба эти списка должны быть представлены в форме, которую способна копировать функция copyObject
. Список fdw_private не имеет других ограничений и никаким образом не интерпретируется ядром сервера. Список fdw_exprs, если этот указатель не NULL, предположительно содержит деревья выражений, которые должны быть вычислены при выполнении запроса. Затем планировщик обрабатывает эти деревья, чтобы они были полностью готовы к выполнению.
GetForeignPlan
обычно может скопировать полученный целевой список в узел плана как есть. Передаваемый список scan_clauses содержит те же предложения, что и baserel->baserestrictinfo, но, возможно, в другом порядке для более эффективного выполнения. В простых случаях FDW может просто убрать узлы RestrictInfo из списка scan_clauses (используя функцию extract_actual_clauses
) и поместить все предложения в список ограничений узла плана, что будет означать, что эти предложения будут проверяться исполнителем во время выполнения. Более сложные FDW могут самостоятельно проверять некоторые предложения, и в этом случае такие предложения можно удалить из списка ограничений узла, чтобы исполнитель не тратил время на их перепроверку.
Например, FDW может распознавать некоторые предложения ограничений вида сторонняя_переменная = подвыражение, которые, по её представлению, могут выполняться на удалённом сервере с локально вычисленным значением подвыражения. Собственно выявление такого предложения должно происходить в функции GetForeignPaths
, так как это влияет на оценку стоимости пути. Эта функция может включить в поле fdw_private конкретного пути указатель на узел RestrictInfo этого предложения. Затем GetForeignPlan
удалит это предложение из scan_clauses, но добавит подвыражение в fdw_exprs, чтобы оно было приведено к исполняемой форме. Она также может поместить управляющую информацию в поле fdw_private плана узла, которая скажет исполняющим функциям, что делать во время выполнения. Запрос, передаваемый удалённому серверу, будет содержать что-то вроде WHERE сторонняя_переменная = $1, а значение параметра будет получено во время выполнения в результате вычисления дерева выражения fdw_exprs.
FDW должна строить минимум один путь, зависящий только от предложений ограничения таблицы. В запросах с соединением она может также построить пути, зависящие от ограничения соединения, например сторонняя_переменная = локальная_переменная. Такие предложения будут отсутствовать в baserel->baserestrictinfo; их нужно искать в списках соединений отношений. Путь, построенный с таким предложением, называется "параметризованным". Другие отношения, задействованные в выбранном предложении соединения, должны связываться c этим путём соответствующим значением param_info; для получения этого значения используется get_baserel_parampathinfo
. В GetForeignPlan
часть локальная_переменная предложения соединения будет добавлена в fdw_exprs, и затем, во время выполнения, это будет работать так же, как и обычное предложение ограничения.
При планировании запросов UPDATE или DELETE PlanForeignModify
может обратиться к структуре RelOptInfo сторонней таблицы и воспользоваться информацией baserel->fdw_private, записанной ранее функциями планирования сканирования. Однако при запросе INSERT целевая таблица не сканируется, так что для неё RelOptInfo не заполняется. На список (List), возвращаемый функцией PlanForeignModify
, накладываются те же ограничения, что и на список fdw_private в узле плана ForeignScan, то есть он должен содержать только такие структуры, которые способна копировать функция copyObject
.
Для действий UPDATE и DELETE во внешнем источнике данных, поддерживающем параллельные изменения, рекомендуется в ForeignScan блокировать строки, выбираемые при этой операции, возможно, выполняя для этого команду вроде SELECT FOR UPDATE. FDW может также решить заблокировать строки в момент выборки, когда сторонняя таблица фигурирует в SELECT FOR UPDATE/SHARE; в противном случае указания FOR UPDATE или FOR SHARE по сути будет бесполезными применительно к данной сторонней таблице. Это поведение может несколько отличаться от операций с локальными таблицами, для которых установка блокировки строк откладывается, насколько это возможно: удалённые строки могут быть заблокированы, даже если они впоследствии не пройдут через локально установленные ограничения или условия соединений. Однако реализация поведения в точности совпадающего с локальным потребовала бы дополнительного удалённого обращения для каждой строки, и всё равно может быть невозможной, в зависимости от режимов блокировки, поддерживаемых внешним источником данным.
Пред. | Начало | След. |
Вспомогательные функции для обёрток сторонних данных | Уровень выше | Генетический оптимизатор запросов |