36.7. Категории волатильности функций#
36.7. Категории волатильности функций #
Каждая функция имеет классификацию volatility, с возможными значениями VOLATILE
, STABLE
или IMMUTABLE
. По умолчанию используется значение VOLATILE
, если команда CREATE FUNCTION
не указывает категорию. Категория volatility - это обещание оптимизатору о поведении функции:
Функция
VOLATILE
может делать все, включая изменение базы данных. Она может возвращать разные результаты при последовательных вызовах с одинаковыми аргументами. Оптимизатор не делает никаких предположений о поведении таких функций. Запрос, использующий волатильную функцию, будет переоценивать функцию для каждой строки, где ее значение требуется.A
STABLE
функция не может изменять базу данных и гарантированно возвращает одинаковые результаты при одинаковых аргументах для всех строк в пределах одного оператора. Эта категория позволяет оптимизатору оптимизировать множественные вызовы функции в один вызов. В частности, безопасно использовать выражение, содержащее такую функцию, в условии сканирования индекса. (Поскольку при сканировании индекса значение сравнения вычисляется только один раз, а не для каждой строки, нельзя использоватьVOLATILE
функцию в условии сканирования индекса).Функция
IMMUTABLE
не может изменять базу данных и гарантированно возвращает одинаковые результаты при одинаковых аргументах навсегда. Эта категория позволяет оптимизатору предварительно вычислить функцию, когда запрос вызывает ее с постоянными аргументами. Например, запрос видаSELECT ... WHERE x = 2 + 2
может быть упрощен доSELECT ... WHERE x = 4
, потому что функция, лежащая в основе оператора сложения целых чисел, помечена какIMMUTABLE
.
Для достижения наилучших результатов оптимизации, вы должны пометить свои функции с наиболее строгой категорией изменчивости, которая для них допустима.
Любая функция с побочными эффектами должна быть помечена
VOLATILE
, чтобы вызовы к ней не могли быть оптимизированы.
Даже функция без побочных эффектов должна быть помечена
VOLATILE
, если ее значение может измениться в рамках одного запроса;
некоторые примеры: random()
, currval()
,
timeofday()
.
Еще одним важным примером является то, что семейство функций current_timestamp
относится к категории STABLE
, так как их значения не изменяются в пределах транзакции.
Между категориями STABLE
и IMMUTABLE
относительно небольшая разница при рассмотрении простых интерактивных запросов, которые планируются и немедленно выполняются: не имеет большого значения, выполняется ли функция один раз во время планирования или один раз при запуске выполнения запроса. Но есть большая разница, если план сохраняется и повторно используется позже. Если функция помечена как IMMUTABLE
, когда на самом деле она не является таковой, это может привести к ее преждевременному сворачиванию в константу во время планирования, что приведет к использованию устаревшего значения при последующем использовании плана. Это опасность при использовании подготовленных операторов или при использовании языков функций, которые кешируют планы (например, PL/pgSQL).
Для функций, написанных на SQL или на любом из стандартных процедурных языков, существует второе важное свойство, определяемое категорией изменчивости, а именно видимость любых изменений данных, сделанных SQL-командой, вызывающей функцию. Функция с категорией изменчивости VOLATILE
будет видеть такие изменения, а функция с категорией изменчивости STABLE
или IMMUTABLE
- нет. Это поведение реализуется с использованием механизма снимков MVCC (см. Глава 13): функции с категорией изменчивости STABLE
и IMMUTABLE
используют снимок, установленный на момент начала вызывающего запроса, тогда как функции с категорией изменчивости VOLATILE
получают свежий снимок в начале каждого выполняемого ими запроса.
Примечание
Функции, написанные на C, могут управлять снимками так, как им удобно, но обычно рекомендуется также сделать так, чтобы C-функции работали таким образом.
Из-за такого поведения снимков, функция, содержащая только команды SELECT
, может быть безопасно помечена как STABLE
, даже если она выбирает из таблиц, которые могут быть изменены параллельными запросами. Tantor SE выполнит все команды функции STABLE
с использованием снимка, установленного для вызывающего запроса, и поэтому будет видеть фиксированное представление базы данных на протяжении всего этого запроса.
То же самое поведение снимков используется для команд SELECT
внутри функций IMMUTABLE
. Вообще говоря, не рекомендуется выбирать данные из таблиц базы данных внутри функции IMMUTABLE
, поскольку неизменяемость будет нарушена, если содержимое таблицы изменится. Однако Tantor SE не обязывает вас не делать этого.
Частой ошибкой является пометка функции как IMMUTABLE
, когда ее результаты зависят от параметра конфигурации. Например, функция, которая обрабатывает временные метки, может зависеть от установки TimeZone. Для безопасности такие функции следует помечать как STABLE
.
Примечание
Tantor SE требует, чтобы функции STABLE
и IMMUTABLE
не содержали SQL-команд, кроме SELECT
, чтобы предотвратить изменение данных.
(Это не полностью надежный тест, так как такие функции могут все равно вызывать функции VOLATILE
, которые изменяют базу данных.
Если вы это сделаете, вы обнаружите, что функция STABLE
или IMMUTABLE
не замечает изменения базы данных, примененные вызываемой функцией, так как они скрыты от ее снимка).