preloader

Optimización de consultas PostgreSQL a escala ERP

Advertisement space

Las bases de datos ERP no son lentas por accidente. Lo son porque los mismos patrones que hacen productivos a los ORM —joins automáticos, carga diferida, resolución de campos calculados— escalan mal contra tablas con millones de filas y filtros complejos de multi-compañía. La solución no es abandonar el ORM. La solución es entender exactamente dónde falla.

Lee el plan de consulta antes de cambiar cualquier cosa

EXPLAIN ANALYZE es el punto de partida para toda investigación de consultas lentas. El plan muestra tiempos reales, estimaciones de filas, estrategias de join y qué nodos hacen escaneos secuenciales en tablas grandes. Un escaneo secuencial en una tabla de cien filas es inofensivo. El mismo escaneo en una tabla de movimientos de stock con diez millones de filas es un problema de presupuesto.

Al leer un plan, hay que buscar estas señales:

  • Escaneos secuenciales en tablas que crecen con el volumen transaccional: movimientos contables, albaranes, líneas de pedido de venta y órdenes de compra.
  • Grandes diferencias entre filas estimadas y reales, que indican estadísticas obsoletas y suelen derivar en estrategias de join incorrectas.
  • Nested loop joins sobre resultados de alta cardinalidad, cuyo coste se multiplica en cadena.
  • Operaciones de ordenación sin índice de respaldo, especialmente sobre columnas de fecha y estado.

El ORM de Odoo genera consultas frecuentemente correctas pero raramente óptimas. La distancia entre correcto y óptimo crece con el tamaño de la tabla.

Por qué los filtros de multi-compañía y estado son costosos sin el índice adecuado

En Odoo, casi todas las consultas llevan filtros implícitos: la compañía, el flag de activo y, a menudo, un estado del ciclo de vida. Estos filtros parecen triviales en Python pero se traducen en condiciones de escaneo nada triviales en SQL cuando el planificador no puede satisfacer las tres condiciones con un solo índice.

Una consulta que filtra movimientos contables por compañía, estado y fecha hará un escaneo completo a menos que exista un índice compuesto que cubra esas columnas en el orden adecuado. Los índices parciales van más lejos: uno filtrado a los movimientos no publicados, o a las órdenes de compra abiertas, es más pequeño y más rápido para los patrones de acceso más habituales.

Las decisiones de indexación deben basarse en planes de consulta, no en intuición. Las columnas que aparecen en cada cláusula WHERE de los caminos críticos —compañía, estado, fecha, partner— merecen cobertura con índices compuestos o parciales. Las que solo aparecen en reportes poco frecuentes, no.

Dónde las consultas generadas por el ORM se vuelven costosas

El ORM de Odoo es una capa de abstracción sobre SQL, y la abstracción tiene un precio. Los campos calculados con subconsultas se evalúan de forma diferida — un acceso a un registro puede generar múltiples viajes si los campos no están precargados. Los campos relacionales many-to-many producen cadenas de joins difíciles de optimizar. La traducción de dominios de búsqueda puede generar condiciones SQL redundantes que impiden el uso de índices.

Las consultas generadas por el ORM más costosas en instancias Odoo en producción comparten algunas características:

  • Agregan sobre tablas transaccionales grandes sin llevar la agregación a una subconsulta o una vista materializada.
  • Filtran sobre campos calculados almacenados que no están indexados, obligando a un escaneo completo de la tabla para cada coincidencia del dominio.
  • Resuelven relaciones many-to-many con cláusulas IN sobre conjuntos grandes, que el planificador suele gestionar peor que un join.
  • Recuperan registros anchos con decenas de columnas cuando solo se necesitan tres o cuatro.

Cuándo pasar a SQL directo

No existe ninguna regla en contra del SQL directo en Odoo. El ORM expone acceso al cursor precisamente para los casos en que la abstracción es contraproducente. Los endpoints de reporting, los jobs de agregación planificados y los dashboards que resumen millones de filas son los candidatos más claros.

El SQL directo es apropiado cuando la consulta requiere funciones de ventana, CTEs o estrategias de agregación que el ORM no puede expresar de forma limpia, o cuando necesita unir tablas eludiendo las reglas de registro con conciencia explícita de los límites de seguridad.

La disciplina es mantener el SQL directo encapsulado y documentado. Una consulta cruda en un método de negocio sin explicación es deuda de mantenimiento. La misma consulta en una capa de reporting dedicada, con una nota que explica por qué se omitió el ORM, sigue siendo legible.

Valida con un volumen de datos similar al de producción

Una consulta que tarda 20 milisegundos en staging con 50.000 registros puede tardar 4 segundos en producción con 8 millones. Esto no es una sorpresa: es una consecuencia predecible de cómo cambia el modelo de costes del planificador con las estadísticas de la tabla. El trabajo de optimización validado solo con datasets pequeños no está terminado.

Probar con volumen realista significa ejecutar los planes contra una copia anonimizada del tamaño de producción, verificar que las estimaciones de filas estén próximas a los valores reales y confirmar que los índices se están usando. También implica tener en cuenta la amplificación de escritura: los índices que mejoran las lecturas añaden sobrecarga en inserciones y actualizaciones, y los sistemas ERP escriben con intensidad.

La optimización de PostgreSQL en contextos ERP no va de una sola consulta rápida. Va de una base de datos que se mantiene ágil a medida que escala el negocio, con planes de consulta elegidos deliberadamente en lugar de heredados de los valores por defecto.

You May Also Like