Перейти к основному содержимому

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

примечание

Эта страница переведена при помощи нейросети GigaChat.

Каждая функция имеет классификацию волатильности, с возможными вариантами VOLATILE, STABLE, или IMMUTABLE. VOLATILE является значением по умолчанию, если команда CREATE FUNCTION не указывает категорию. Категория волатильности представляет собой обещание оптимизатору относительно поведения функции:

  • Функция VOLATILE может делать все что угодно, включая изменение базы данных. Она может возвращать разные результаты при последовательных вызовах с одинаковыми аргументами. Оптимизатор не делает никаких предположений о поведении таких функций. Запрос, использующий изменчивую функцию, будет повторно оценивать эту функцию для каждой строки, где требуется ее значение.
  • Функция 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: функции STABLE и IMMUTABLE используют снимок, установленный начиная с начала запроса вызова, тогда как функции VOLATILE получают свежий снимок в начале каждого выполняемого ими запроса.

Примечание

Функции, написанные на языке Cи, могут управлять моментальными снимками так, как они хотят, но обычно это хорошая идея сделать так, чтобы функции на языке Cи работали таким же образом.

Из-за такого поведения моментального снимка, функция, содержащая только команды SELECT, может быть безопасно помечена как STABLE, даже если она выбирает данные из таблиц, которые могут подвергаться изменениям параллельными запросами. PostgreSQL будет выполнять все команды функции STABLE с использованием моментального снимка, установленного для запроса вызова, и поэтому он будет видеть фиксированный вид базы данных в течение всего этого запроса.

То же самое поведение моментальных снимков используется для команд SELECT внутри функций IMMUTABLE. В целом неразумно выбирать данные из таблиц баз данных внутри функции IMMUTABLE, поскольку неизменность будет нарушена, если когда-либо изменится содержимое таблицы. Однако PostgreSQL не требует, чтобы этого не делали.

Обычной ошибкой является маркировка функции как IMMUTABLE, когда ее результаты зависят от параметра конфигурации. Например, функция, манипулирующая метками времени, вполне может иметь результаты, зависящие от настройки TimeZone. Для безопасности такие функции должны быть помечены как STABLE вместо этого.

Примечание

PostgreSQL требует, чтобы функции STABLE и IMMUTABLE содержали только команды SQL, отличные от SELECT, для предотвращения изменения данных (это не полностью надежное испытание, так как эти функции все равно могут вызывать функции VOLATILE, которые изменяют базу данных. Если это сделать, то обнаружите, что функция STABLE или IMMUTABLE не замечает изменений в базе данных, внесенных вызванной функцией, поскольку они скрыты от ее моментального снимка).