36.7. Categorías de volatilidad de las funciones #

Cada función tiene una clasificación de volatilidad, siendo las opciones posibles VOLATILE, STABLE o IMMUTABLE. VOLATILE es el valor por defecto si el comando CREATE FUNCTION no especifica una categoría. La categoría de volatilidad es una promesa al optimizador sobre el comportamiento de la función:

Para obtener los mejores resultados de optimización, debes etiquetar tus funciones con la categoría de volatilidad más estricta que sea válida para ellas.

Cualquier función con efectos secundarios debe etiquetarse como VOLATILE, para que las llamadas a ella no puedan optimizarse. Incluso una función sin efectos secundarios debe etiquetarse como VOLATILE si su valor puede cambiar dentro de una sola consulta; algunos ejemplos son random(), currval(), timeofday().

Otro ejemplo importante es que la familia de funciones current_timestamp califica como STABLE, ya que sus valores no cambian dentro de una transacción.

Existe relativamente poca diferencia entre las categorías STABLE e IMMUTABLE cuando se consideran consultas interactivas simples que se planifican y ejecutan inmediatamente: no importa mucho si una función se ejecuta una vez durante la planificación o una vez durante el inicio de la ejecución de la consulta. Pero hay una gran diferencia si el plan se guarda y se reutiliza más tarde. Etiquetar una función como IMMUTABLE cuando realmente no lo es podría permitir que se convierta prematuramente en una constante durante la planificación, lo que daría como resultado la reutilización de un valor obsoleto en usos posteriores del plan. Esto es un peligro cuando se utilizan sentencias preparadas o cuando se utilizan lenguajes de función que almacenan en caché los planes (como PL/pgSQL).

Para las funciones escritas en SQL o en cualquiera de los lenguajes procedimentales estándar, existe una segunda propiedad importante determinada por la categoría de volatilidad, a saber, la visibilidad de los cambios de datos que hayan sido realizados por el comando SQL que está llamando a la función. Una función VOLATILE verá dichos cambios, una función STABLE o IMMUTABLE no lo hará. Este comportamiento se implementa utilizando el comportamiento de toma de instantáneas de MVCC (consulta la Chapter 13): las funciones STABLE e IMMUTABLE utilizan una instantánea establecida al inicio de la consulta invocadora, mientras que las funciones VOLATILE obtienen una instantánea fresca al inicio de cada consulta que ejecutan.

Note

Las funciones escritas en C pueden gestionar las instantáneas como deseen, pero normalmente es una buena idea hacer que las funciones en C también funcionen de esta manera.

Debido a este comportamiento de instantáneas, una función que contiene solo comandos SELECT se puede marcar de forma segura como STABLE, incluso si selecciona de tablas que podrían estar experimentando modificaciones por consultas concurrentes. PostgreSQL ejecutará todos los comandos de una función STABLE utilizando la instantánea establecida para la consulta invocadora, por lo que verá una vista fija de la base de datos a lo largo de esa consulta.

El mismo comportamiento de instantáneas se utiliza para los comandos SELECT dentro de funciones IMMUTABLE. En general, no es recomendable seleccionar de tablas de la base de datos dentro de una función IMMUTABLE, ya que la inmutabilidad se romperá si el contenido de la tabla cambia alguna vez. Sin embargo, PostgreSQL no impide que hagas eso.

Un error común es etiquetar una función como IMMUTABLE when sus resultados dependen de un parámetro de configuración. Por ejemplo, una función que manipula marcas de tiempo podría tener resultados que dependan de la configuración de TimeZone. Por seguridad, estas funciones deberían etiquetarse como STABLE en su lugar.

Note

PostgreSQL requiere que las funciones STABLE e IMMUTABLE no contengan más comandos SQL que SELECT para evitar la modificación de datos. (Esta no es una prueba completamente infalible, ya que dichas funciones aún podrían invocar funciones VOLATILE que modifiquen la base de datos. Si haces eso, verás que la función STABLE o IMMUTABLE no nota los cambios en la base de datos aplicados por la función llamada, ya que están ocultos para su instantánea).