La siguiente extensión de su código de prueba es de carácter informativo:
CREATE OR REPLACE FUNCTION test_multi_calls1(one integer)
RETURNS integer
AS $BODY$
BEGIN
RAISE NOTICE 'Immutable called with %', one;
RETURN one;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION test_multi_calls2(one integer)
RETURNS integer
AS $BODY$
BEGIN
RAISE NOTICE 'Volatile called with %', one;
RETURN one;
END;
$BODY$ LANGUAGE plpgsql VOLATILE;
WITH data AS
(
SELECT 10 AS num
UNION ALL SELECT 10
UNION ALL SELECT 20
)
SELECT test_multi_calls1(num)
FROM data
where test_multi_calls2(40) = 40
and test_multi_calls1(30) = 30
SALIDA:
NOTICE: Immutable called with 30
NOTICE: Volatile called with 40
NOTICE: Immutable called with 10
NOTICE: Volatile called with 40
NOTICE: Immutable called with 10
NOTICE: Volatile called with 40
NOTICE: Immutable called with 20
Aquí podemos ver que mientras que en la lista de selección de la función inmutable fue llamado varias veces, en la cláusula where se llamó una vez, mientras que la volátil se llamó tres veces.
Lo importante no es que PostgreSQL sólo llamar a una función o STABLE
IMMUTABLE
una vez con los mismos datos - el ejemplo muestra claramente que este no es el caso - es que puede llamar una sola vez. O tal vez lo llame dos veces cuando tenga que llamar a una versión volátil 50 veces, y así sucesivamente.
Existen diferentes formas de aprovechar la estabilidad y la inmutabilidad, con diferentes costos y beneficios. Para proporcionar el tipo de ahorro que está sugiriendo que debería hacer con listas de selección, tendría que almacenar en caché los resultados y luego buscar cada argumento (o lista de argumentos) en este caché antes de devolver el resultado en caché o la función de llamada en un caché -perder. Esto sería más costoso que llamar a su función, incluso en el caso de que hubiera un alto porcentaje de aciertos de caché (podría haber 0% de aciertos de caché, lo que significa que esta "optimización" hizo un trabajo adicional sin ningún beneficio). Podría almacenar quizás solo el último parámetro y resultado, pero nuevamente eso podría ser completamente inútil.
Esto es especialmente así, teniendo en cuenta que las funciones estables e inmutables son a menudo las funciones más ligeras.
Con la cláusula where sin embargo, la inmutabilidad de test_multi_calls1
permite que PostgreSQL realidad reestructurar la consulta desde el sentido corriente del SQL dada:
Para cada fila calcular test_multi_calls1 (30) y si el resultado es igual a 30 continuar con la tramitación de la fila en cuestión
para un plan de consulta completamente diferente:
Calcular test_multi_calls1 (30) y si es igual a 30 entonces continuar con la consulta devolverían una configuración de resultados de fila cero sin cualquier otro cálculo
Este es el tipo de uso que PostgreSQL hace de estable y INMUTABLE: no el almacenamiento en caché de los resultados, sino la reescritura de las consultas en diferentes consultas que son más eficientes pero dan los mismos resultados.
Tenga en cuenta también que test_multi_calls1 (30) se llama before test_multi_calls2 (40) sin importar el orden en que aparecen en la cláusula where. Esto significa que si la primera llamada no devuelve filas (reemplace = 30
con = 31
para probar), la función volátil no se volverá a llamar, de nuevo, independientemente de cuál sea el lado del and
.
Este tipo particular de reescritura depende de la inmutabilidad o la estabilidad. Con where test_multi_calls1(30) != num
, la reescritura de consultas ocurrirá para funciones inmutables pero no solo para funciones estables. Con where test_multi_calls1(num) != 30
no sucederá en absoluto (llamadas múltiples), aunque hay otras optimizaciones posibles:
Las expresiones que contienen solo funciones ESTABLE e IMMUTABLE se pueden usar con escaneos de índice. Las expresiones que contienen funciones VOLATILES no pueden. El número de llamadas puede o no disminuir, pero mucho más importante es que los resultados de las llamadas se utilizarán de una manera mucho más eficiente en el resto de la consulta (solo importa en tablas grandes, pero luego puede generar una gran cantidad de llamadas). diferencia).
En general, no piense en categorías de volatilidad en términos de memorización, sino en términos de dar oportunidades de PostgreSQL al planificador de consultas para reestructurar consultas completas de forma que sean lógicamente equivalentes (mismos resultados) pero mucho más eficientes.
Cosas interesantes –