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