36.7. Категории волатильности функций#

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 не замечает изменения базы данных, примененные вызываемой функцией, так как они скрыты от ее снимка).