Информация об оптимизации функций
Эта страница переведена при помощи нейросети GigaChat.
По умолчанию функция представляет собой просто «черный ящик», о поведении которого система баз данных знает очень мало. Однако это означает, что запросы, использующие функцию, могут выполняться гораздо менее эффективно, чем могли бы быть. Возможно предоставить дополнительную информацию, которая помогает планировщику оптимизировать вызовы функций.
Некоторые основные факты могут быть предоставлены декларативными аннотациями, предоставляемыми в команде CREATE FUNCTION
. Наиболее важным из них является (характеристика изменчивости; IMMUTABLE
, STABLE
, или VOLATILE
); всегда следует тщательно указывать это при определении функции. Свойство параллельной безопасности (PARALLEL UNSAFE
, PARALLEL RESTRICTED
, или PARALLEL SAFE
) также должно быть указано, если надеетесь использовать функцию в параллельном запросе. Также может быть полезно указать предполагаемую стоимость выполнения функции и/или количество строк, которые, по оценкам, будет возвращать функция, возвращающая набор. Однако декларативный способ указания этих двух фактов позволяет указывать только постоянное значение, что часто недостаточно.
Также возможно прикрепить функцию поддержки планировщика к вызываемой функцией SQL (она будет целевой функцией для первой) и тем самым предоставить информацию о целевой функции, которая слишком сложна для декларативного представления. Функции поддержки планировщика должны быть написаны на языке C (хотя их целевые функции могут быть написаны на любом языке), поэтому это сложная функция, которую будут использовать лишь немногие люди.
Вспомогательная функция должна иметь в SQL такую сигнатуру:
supportfn(internal) returns internal
Она связывается с целевой функцией с помощью указания SUPPORT
в команде, создающей целевую функцию.
Подробную информацию об API для функций поддержки планировщика можно найти в файле src/include/nodes/supportnodes.h
в исходном коде PostgreSQL. Здесь представлен лишь обзор того, что могут делать функции поддержки планировщика. Набор возможных запросов к функции поддержки расширяемый, поэтому в будущих версиях может быть возможно больше возможностей.
Некоторые вызовы функций могут быть упрощены во время планирования на основе свойств, специфичных для функции. Например, int4mul(n, 1)
может быть упрощен до просто n
. Этот тип преобразования может быть выполнен функцией поддержки планировщика путем реализации типа запроса SupportRequestSimplify
. Функция поддержки будет вызвана для каждого экземпляра своей целевой функции, найденной в дереве разбора запроса. Если она обнаружит, что конкретный вызов может быть упрощен до некоторой другой формы, она может создать и вернуть дерево разбора, представляющее это выражение. Это автоматически сработает и для операторов, основанных на этой функции, тоже – в приведенном выше примере n * 1
также был бы упрощен до n
. (Но обратите внимание, что это всего лишь пример; эта конкретная оптимизация фактически не выполняется стандартной PostgreSQL.) Не гарантируется, что PostgreSQL никогда не вызовет целевую функцию в случаях, которые функция поддержки могла бы упростить. Обеспечьте строгое соответствие между упрощенным выражением и фактическим выполнением целевой функции.
Для целевых функций, возвращающих boolean
, часто бывает полезно оценить долю строк, которые будут выбраны с помощью условия WHERE
с использованием этой функции. Это можно сделать с помощью функции поддержки, которая реализует тип запроса SupportRequestSelectivity
.
Если время выполнения целевой функции сильно зависит от ее входных данных, может быть полезно предоставить оценку стоимости, отличную от постоянной. Это можно сделать с помощью вспомогательной функции, которая реализует тип запроса SupportRequestCost
.
Для целевых функций, которые возвращают наборы, часто бывает полезно предоставить непостоянную оценку количества строк, которые будут возвращены. Это можно сделать с помощью вспомогательной функции, которая реализует тип запроса SupportRequestRows
.
Для целевых функций, которые возвращают boolean
, возможно, удастся преобразовать вызов функции, появляющийся в WHERE
, в индексируемый операторный блок или блоки. Преобразованные условия могут быть точно эквивалентны условию функции, либо они могут быть несколько слабее (то есть они могут принимать некоторые значения, которые условие функции не принимает). В последнем случае условие индекса называется потерянным; его все равно можно использовать для сканирования индекса, но вызов функции придется выполнять для каждой строки, возвращаемой индексом, чтобы увидеть, действительно ли она удовлетворяет условию WHERE
или нет. Для создания таких условий вспомогательная функция должна реализовать тип запроса SupportRequestIndexCondition
.