Как ключевые слова IMMUTABLE, STABLE и VOLATILE влияют на поведение функции?

Мы написали функцию get_timestamp(), определенную как

CREATE OR REPLACE FUNCTION get_timestamp()
  RETURNS integer AS
$$
SELECT (FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 10) - 13885344000)::int;
$$
LANGUAGE SQL;

Это использовалось для INSERT и UPDATE для ввода или редактирования значения в созданном и измененном поле в записи базы данных. Однако при добавлении или обновлении записей мы обнаружили, что оно возвращало одно и то же значение.

При проверке функции в pgAdmin III мы отметили, что при запуске SQL для построения функции ключевое слово IMMUTABLE было введено после оператора SQL ЯЗЫК. В документации указано, что значением по умолчанию является VOLATILE (Если ни одно из них не появляется, VOLATILE является предположением по умолчанию), поэтому я не уверен, почему IMTUTABLE был введен, однако изменение этого параметра на STABLE решило проблему повторяющихся значений.

ПРИМЕЧАНИЕ. Как указано в принятом ответе, IMMUTABLE никогда не добавляется к функции через pgAdmin или Postgres и должен быть добавлен во время разработки.

Я предполагаю, что происходит то, что эта функция была оценена, и результат был кэширован для оптимизации, поскольку он был помечен IMMUTABLE, указывающий движку Postgres, что возвращаемое значение не должно изменяться с учетом того же (пустого) списка параметров, Однако, когда он не используется в триггере, когда он используется непосредственно в инструкции INSERT, функция возвращает четное значение FIVE раз, а затем возвращает то же самое значение с этого момента. Это связано с некоторым алгоритмом оптимизации, который говорит что-то вроде "Если функция IMMUTABLE используется более 5 раз в сеансе, кешируйте результат для будущих вызовов"?

Любые разъяснения относительно того, как эти ключевые слова должны использоваться в функциях Postgres, будут оценены. Является ли STABLE правильным вариантом для нас, учитывая, что мы используем эту функцию в триггерах, или есть что-то большее, чтобы рассмотреть, например, документы говорят:

(Неправильно для триггеров AFTER, которые хотят запрашивать строки измененный текущей командой.)

Но я не совсем понимаю, почему.

Ответ 1

Ключевое слово IMMUTABLE: никогда автоматически добавляется pgAdmin или Postgres. Кто когда-либо создал или заменил функцию, сделал это.

Правильная функция волатильности (чтение руководства) для данной функции VOLATILE, а не STABLE - или не имеет смысла использовать clock_timestamp(), который равен VOLATILE, а не now() или CURRENT_TIMESTAMP, которые определены STABLE: те вернуть те же временные метки в рамках одной транзакции, для документации:

clock_timestamp() возвращает фактическое текущее время, и поэтому его изменение значений даже в пределах одной команды SQL.

Руководство предупреждает, что волатильность функции STABLE...

не подходит для AFTER триггеров, которые хотят запросить строки, модифицированные текущей командой.

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

И вы спрашиваете:

Есть ли у вас идея, почему функция вернулась правильно? раз, прежде чем приклеивать пятое значение при установке IMMUTABLE?

Цитата Postgres Wiki:

С 9.2 планировщик будет использовать конкретные планы относительно отправленные параметры (запрос будет запланирован при выполнении), за исключением случаев, когда запрос выполняется несколько раз, и планировщик решает, что общий план не слишком дороже, чем конкретные планы.

Смелый акцент мой. Кажется, не имеет смысла для функции IMMUTABLE (также не наносит вреда), но, возможно, использование функции VOLATILE внутри все еще вызывает первоначальное перепланирование. (Последний бит - это только мои предположения.)
Больше объяснений здесь:

Помимо

trunc() немного быстрее, чем floor(), и делает то же самое здесь, так как положительные числа гарантированы:

SELECT (trunc(EXTRACT(EPOCH FROM clock_timestamp()) * 10) - 13885344000)::int