36.11. Información de optimización de funciones #

Por defecto, una función es solo una caja negra de cuyo comportamiento el sistema de base de datos sabe muy poco. Sin embargo, eso significa que las consultas que utilizan la función pueden ejecutarse de manera mucho menos eficiente de lo que podrían. Es posible proporcionar información adicional que ayude al planificador a optimizar las llamadas a las funciones.

Algunos datos básicos se pueden suministrar mediante anotaciones declarativas proporcionadas en el comando CREATE FUNCTION. La más importante de ellas es la categoría de volatilidad de la función (IMMUTABLE, STABLE o VOLATILE); siempre se debe tener cuidado de especificar esto correctamente al definir una función. La propiedad de seguridad en paralelo (PARALLEL UNSAFE, PARALLEL RESTRICTED o PARALLEL SAFE) también debe especificarse si esperas utilizar la función en consultas paralelizadas. También puede ser útil especificar el costo estimado de ejecución de la función y/o el número de filas que se estima que devolverá una función que devuelve un conjunto. Sin embargo, la forma declarativa de especificar esos dos datos solo permite indicar un valor constante, lo que a menudo es inadecuado.

También es posible acoplar una función de soporte del planificador (planner support function) a una función invocable por SQL (llamada su función objetivo), y así proporcionar información sobre la función objetivo que es demasiado compleja para ser representada declarativamente. Las funciones de soporte del planificador tienen que escribirse en C (aunque sus funciones objetivo podrían no estarlo), por lo que esta es una característica avanzada que utilizarán relativamente pocas personas.

Una función de soporte del planificador debe tener la firma SQL:

supportfn(internal) returns internal

Se acopla a su función objetivo especificando la cláusula SUPPORT al crear la función objetivo.

Los detalles de la API para las funciones de soporte del planificador se pueden encontrar en el archivo src/include/nodes/supportnodes.h en el código fuente de PostgreSQL. Aquí proporcionamos solo una descripción general de lo que pueden hacer las funciones de soporte del planificador. El conjunto de solicitudes posibles a una función de soporte es extensible, por lo que podrían ser posibles más cosas en futuras versiones.

Algunas llamadas a funciones se pueden simplificar durante la planificación basándose en propiedades específicas de la función. Por ejemplo, int4mul(n, 1) podría simplificarse a solo n. Este tipo de transformación puede ser realizada por una función de soporte del planificador, haciendo que implemente el tipo de solicitud SupportRequestSimplify. La función de soporte se llamará por cada instancia de su función objetivo que se encuentre en un árbol de análisis de consulta. Si determina que la llamada en particular se puede simplificar en alguna otra forma, puede construir y devolver un árbol de análisis que represente esa expresión. Esto también funcionará automáticamente para los operadores basados en la función; en el ejemplo que acabamos de dar, n * 1 también se simplificaría a n. (Pero ten en cuenta que esto es solo un ejemplo; esta optimización en particular no la realiza realmente el PostgreSQL estándar). No garantizamos que PostgreSQL nunca llame a la función objetivo en los casos en que la función de soporte podría simplificarla. Asegura una equivalencia rigurosa entre la expresión simplificada y la ejecución real de la función objetivo.

Para las funciones objetivo que devuelven boolean, a menudo es útil estimar la fracción de filas que serán seleccionadas por una cláusula WHERE que utilice esa función. Esto lo puede hacer una función de soporte que implemente el tipo de solicitud SupportRequestSelectivity.

Si el tiempo de ejecución de la función objetivo depende en gran medida de sus entradas, puede ser útil proporcionar una estimación de costo no constante para ella. Esto lo puede hacer una función de soporte que implemente el tipo de solicitud SupportRequestCost.

Para las funciones objetivo que devuelven conjuntos, a menudo es útil proporcionar una estimación no constante del número de filas que se devolverán. Esto lo puede hacer una función de soporte que implemente el tipo de solicitud SupportRequestRows.

Para las funciones objetivo que devuelven boolean, puede ser posible convertir una llamada a la función que aparece en un WHERE en una cláusula o cláusulas de operador indexables. Las cláusulas convertidas pueden ser exactamente equivalentes a la condición de la función, o podrían ser algo más débiles (es decir, podrían aceptar algunos valores que la condición de la función no acepta). En este último caso, se dice que la condición de índice es pérdida (lossy); aún se puede utilizar para escanear un índice, pero la llamada a la función tendrá que ejecutarse para cada fila devuelta por el índice para comprobar si realmente pasa la condición del WHERE o no. Para crear tales condiciones, la función de soporte debe implementar el tipo de solicitud SupportRequestIndexCondition.