Viniendo de un entorno MySQL, donde el rendimiento del procedimiento almacenado (artículo anterior) y la usabilidad son cuestionables, estoy evaluando PostgreSQL para un nuevo producto para mi empresa.
Una de las cosas que me gustaría hacer es mover parte de la lógica de la aplicación a los procedimientos almacenados, por lo que estoy pidiendo DO y NO (mejores prácticas) sobre el uso de funciones en PostgreSQL (9.0), específicamente con respecto a las dificultades de rendimiento.
postgresql
best-practices
plpgsql
Derek Downey
fuente
fuente
Respuestas:
Estrictamente hablando, el término "procedimientos almacenados" apunta a procedimientos SQL en Postgres, introducido con Postgres 11. Relacionado:
También hay funciones que hacen casi, pero no exactamente lo mismo, y que han estado allí desde el principio.
Las funciones con
LANGUAGE sql
son básicamente archivos por lotes con comandos SQL simples en un contenedor de funciones (y, por lo tanto, atómico, siempre se ejecutan dentro de una sola transacción) que aceptan parámetros. Todas las declaraciones en una función SQL se planifican a la vez , lo que es sutilmente diferente de ejecutar una declaración después de la otra y puede afectar el orden en que se toman los bloqueos.Para cualquier otra cosa, el lenguaje más maduro es PL / pgSQL (
LANGUAGE plpgsql
). Funciona bien y se ha mejorado con cada lanzamiento en la última década, pero sirve mejor como pegamento para los comandos SQL. No está destinado a cálculos pesados (que no sean con comandos SQL).Las funciones PL / pgSQL ejecutan consultas como declaraciones preparadas . Reutilizar los planes de consulta en caché reduce algunos gastos generales de planificación y los hace un poco más rápidos que las declaraciones SQL equivalentes, lo que puede ser un efecto notable dependiendo de las circunstancias. También puede tener efectos secundarios como en esta pregunta relacionada:
Esto conlleva las ventajas y desventajas de las declaraciones preparadas, como se explica en el manual . Para consultas en tablas de datos con distribución irregular y parámetros variables SQL dinámico con
EXECUTE
puede funcionar mejor cuando la ganancia de un plan de ejecución optimizado para el parámetro determinado (s) es mayor que el costo de la replanificación.Dado que los planes de ejecución genéricos de Postgres 9.2 todavía se almacenan en caché para la sesión pero, citando el manual :
Obtenemos lo mejor de ambos mundos la mayor parte del tiempo (menos algunos gastos generales adicionales) sin (ab) usar
EXECUTE
. Detalles en Novedades de PostgreSQL 9.2 de PostgreSQL Wiki .Postgres 12 presenta la variable de servidor
plan_cache_mode
adicional para forzar planes genéricos o personalizados. Para casos especiales, usar con cuidado.Puede ganar en grande con las funciones del lado del servidor que evitan los viajes de ida y vuelta adicionales al servidor de la base de datos desde su aplicación. Haga que el servidor ejecute tanto como sea posible a la vez y solo devuelva un resultado bien definido.
Evite anidar funciones complejas, especialmente funciones de tabla (
RETURNING SETOF record
oTABLE (...)
). Las funciones son cajas negras que se presentan como barreras de optimización para el planificador de consultas. Se optimizan por separado, no en el contexto de la consulta externa, lo que simplifica la planificación, pero puede dar como resultado planes menos que perfectos. Además, el costo y el tamaño del resultado de las funciones no se pueden predecir de manera confiable.La excepción a esta regla son las funciones simples de SQL (
LANGUAGE sql
), que pueden " integrarse " , si se cumplen algunas condiciones previas . Lea más sobre cómo funciona el planificador de consultas en esta presentación de Neil Conway (material avanzado).En PostgreSQL, una función siempre se ejecuta automáticamente dentro de una sola transacción . Todo tiene éxito o nada. Si ocurre una excepción, todo se revierte. Pero hay un manejo de errores ...
Esa es también la razón por la cual las funciones no son exactamente "procedimientos almacenados" (aunque ese término se usa a veces, de manera engañosa). Algunos comandos gusta
VACUUM
,CREATE INDEX CONCURRENTLY
oCREATE DATABASE
no se puede ejecutar dentro de un bloque de transacción, por lo que no están permitidos en funciones. (Ni en los procedimientos SQL, todavía, a partir de Postgres 11. Eso podría agregarse más adelante).He escrito miles de funciones plpgsql a lo largo de los años.
fuente
Algunas DO:
fuente
En términos generales, mover la lógica de la aplicación a la base de datos significará que es más rápido; después de todo, se ejecutará más cerca de los datos.
Creo (pero no estoy 100% seguro) de que las funciones del lenguaje SQL son más rápidas que las que usan otros idiomas porque no requieren cambio de contexto. La desventaja es que no se permite ninguna lógica de procedimiento.
PL / pgSQL es el más maduro y completo de los lenguajes integrados, pero para el rendimiento, se puede usar C (aunque solo beneficiará a funciones computacionalmente intensivas)
fuente
Puede hacer cosas muy interesantes utilizando funciones definidas por el usuario (UDF) en postgresql. Por ejemplo, hay docenas de idiomas posibles que puede usar. Los pl / sql y pl / pgsql integrados son capaces y confiables y utilizan un método de sandbox para evitar que los usuarios hagan algo demasiado peligroso. Los UDF escritos en C le brindan lo último en potencia y rendimiento, ya que se ejecutan en el mismo contexto que la base de datos. Sin embargo, es como jugar con fuego, porque incluso los pequeños errores pueden causar grandes problemas, con fallas en el backends o la corrupción de los datos. Los personalizados idiomas pl, como pl / R, pl / ruby, pl / perl, etc., le brindan la capacidad de escribir capas de bases de datos y aplicaciones en los mismos idiomas. Esto puede ser útil, ya que significa que no tiene que enseñarle a un programador perl java o pl / pgsql, etc. para escribir un UDF.
Por último, está el lenguaje pl / proxy . Este lenguaje UDF le permite ejecutar su aplicación en docenas o más servidores back-end postgresql para fines de escala. Fue desarrollado por la gente buena de Skype y básicamente permite la solución de escalado horizontal de un hombre pobre. Es sorprendentemente fácil escribir también.
Ahora, en cuanto al problema de rendimiento. Esta es un área gris. ¿Estás escribiendo una aplicación para una persona? ¿O por 1,000? o por 10,000,000? La forma en que crea su aplicación y utiliza UDF dependerá MUCHO de cómo está tratando de escalar. Si está escribiendo para miles y miles de usuarios, entonces lo principal que desea hacer es reducir la carga en la base de datos tanto como sea posible. Los UDF que reducen la cantidad de datos que se mueven y regresan a la base de datos ayudarán a reducir la carga de E / S. Sin embargo, si comienzan a aumentar la carga de la CPU, pueden ser un problema. En términos generales, reducir la carga de E / S es la primera prioridad, y asegurarse de que las UDF sean eficientes para no sobrecargar sus CPU es el siguiente.
fuente