35.10. Информация об оптимизации функций#
35.10. Информация об оптимизации функций #
По умолчанию, функция - это просто “черный ящик”, о поведении которого базовая система баз данных знает очень мало. Однако это означает, что запросы, использующие функцию, могут выполняться намного менее эффективно, чем могли бы. Возможно предоставить дополнительные знания, которые помогут планировщику оптимизировать вызовы функций.
Некоторые основные факты можно указать в декларативных аннотациях, предоставляемых в команде 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
в исходном коде Tantor BE. Здесь мы предоставляем только обзор того, что могут делать функции поддержки планировщика. Набор возможных запросов к функции поддержки может быть расширен, поэтому в будущих версиях могут быть доступны и другие возможности.
Некоторые вызовы функций могут быть упрощены во время планирования на основе свойств, специфичных для функции. Например, int4mul(n, 1)
может быть упрощено до просто n
. Этот тип преобразования может быть выполнен с помощью функции поддержки планировщика, реализующей тип запроса SupportRequestSimplify
. Опорная функция будет вызываться для каждого экземпляра целевой функции, найденного в дереве разбора запроса. Если она обнаружит, что конкретный вызов может быть упрощен до другой формы, она может построить и вернуть дерево разбора, представляющее это выражение. Это также автоматически работает для операторов, основанных на функции - в приведенном примере n * 1
также будет упрощено до n
. (Но обратите внимание, что это всего лишь пример; эту конкретную оптимизацию фактически не выполняет стандартный Tantor BE). Мы не гарантируем, что Tantor BE никогда не будет вызывать целевую функцию в случаях, когда Опорная функция может упростить ее. Обеспечьте строгую эквивалентность между упрощенным выражением и фактическим выполнением целевой функции.
Для целевых функций, которые возвращают boolean
, часто полезно оценить долю строк, которые будут выбраны с помощью WHERE
условия, используя эту функцию. Это можно сделать с помощью вспомогательной функции, которая реализует тип запроса SupportRequestSelectivity
.
Если время выполнения целевой функции сильно зависит от ее входных данных,
может быть полезно предоставить не постоянную оценку стоимости для нее.
Это можно сделать с помощью функции поддержки, которая реализует
тип запроса SupportRequestCost
.
Для целевых функций, возвращающих наборы, часто полезно предоставить
не постоянную оценку количества строк, которые будут возвращены.
Это можно сделать с помощью вспомогательной функции, которая реализует
тип запроса SupportRequestRows
.
Для целевых функций, которые возвращают boolean
, возможно преобразование вызова функции, появляющегося в WHERE
, в индексируемое условие или несколько условий. Преобразованные условия могут быть точно эквивалентны условию функции, или они могут быть несколько слабее (то есть, они могут принимать некоторые значения, которые не принимает условие функции). В последнем случае говорят, что индексное условие является потерянным; оно все равно может использоваться для сканирования индекса, но вызов функции должен быть выполнен для каждой строки, возвращенной индексом, чтобы увидеть, проходит ли она действительно условие WHERE
или нет. Для создания таких условий, поддерживающая функция должна реализовать тип запроса SupportRequestIndexCondition
.