Optimización de Rendimiento en Odoo
Odoo es una plataforma poderosa, pero su rendimiento depende directamente de cómo se configure y optimice. Un sistema lento frustra a los usuarios y reduce la productividad. Este artículo cubre las estrategias más efectivas para acelerar Odoo: desde el caching y la optimización de consultas SQL hasta la configuración de workers, cron jobs y monitoreo de rendimiento.
1. Diagnóstico del Rendimiento Actual
Antes de optimizar, necesitas saber dónde está el problema. Odoo incluye herramientas integradas para medir el rendimiento. Habilita el modo debug accediendo a Ajustes, Activar modo de depuración, o agregando ?debug=1 a la URL. En el modo debug, aparece un menú con estadísticas de tiempo de respuesta por petición.
También puedes habilitar el profiling en odoo.conf para capturar métricas detalladas de cada petición. Esto genera archivos de profiling que puedes analizar con herramientas como py-spy o cProfile para identificar exactamente qué función consume más tiempo en cada vista y método del ORM.
Para monitorear en tiempo real las consultas lentas de PostgreSQL, configura el log de consultas lentas en postgresql.conf con el parámetro log_min_duration_statement = 200 para registrar todas las consultas que superen los 200 milisegundos. Luego analiza los resultados con pgBadger o busca patrones en el log para detectar cuellos de botella recurrentes.
2. Optimización de Consultas SQL
Las consultas lentas son la causa más común de lentitud en Odoo. Los problemas más comunes incluyen falta de índices en campos de búsqueda frecuente, JOINs innecesarios en herencias complejas, y filtros aplicados sobre campos no indexados que obligan a PostgreSQL a escaneos completos de tabla.
Usa EXPLAIN ANALYZE para detectar seq scans en las consultas más lentas. El comando muestra el plan de ejecución real de PostgreSQL, incluyendo el costo estimado, el número de filas procesadas y el tiempo real de ejecución. Presta especial atención a las líneas que muestran "Seq Scan" en tablas grandes, ya que indican la necesidad de crear índices adicionales.
Ejemplo de análisis con EXPLAIN ANALYZE:
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT p.name, SUM(l.price_unit * l.qty) as total
FROM sale_order_line l
JOIN sale_order p ON l.order_id = p.id
WHERE p.date_order >= '2025-01-01'
GROUP BY p.name
ORDER BY total DESC
LIMIT 50;
3. Índices en PostgreSQL para Odoo
Odoo crea algunos índices automáticamente, pero muchos campos de búsqueda frecuente quedan sin índice. Crea índices personalizados usando CONCURRENTLY para evitar bloqueos en producción:
CREATE INDEX CONCURRENTLY idx_sale_order_date
ON sale_order(date_order);
CREATE INDEX CONCURRENTLY idx_sale_order_state
ON sale_order(state);
CREATE INDEX CONCURRENTLY idx_account_move_partner
ON account_move(partner_id, state);
CREATE INDEX CONCURRENTLY idx_stock_picking_state
ON stock_picking(state, scheduled_date);
Los índices parciales son especialmente útiles para consultas que filtran por estados específicos, ya que son más pequeños y más rápidos que los índices completos. También monitorea los índices no utilizados y elimina los que no se usan para liberar espacio en disco.
4. Configuración de Workers y Procesos
Los workers de Odoo gestionan las peticiones HTTP de forma concurrente. Cada worker consume entre 200 y 400 MB de RAM. Un servidor con 16 GB de RAM (con PostgreSQL usando 4 GB) puede soportar cómodamente 6-8 workers. Usa htop para monitorear el consumo real de memoria.
[options]
workers = 8
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_request = 8192
limit_time_cpu = 120
limit_time_real = 300
limit_time_real_cron = 300
Los workers se reciclan automáticamente cuando alcanzan limit_request o limit_time_cpu, lo que previene memory leaks en peticiones largas. Ajusta estos valores según la complejidad de tus módulos personalizados y el volumen de usuarios concurrentes.
5. Sistema de Caching en Odoo
Odoo utiliza Redis como backend de cache para almacenar datos frecuentemente consultados como listas de precios, configuraciones de empresa y datos de sesiones. Instala Redis en Ubuntu y configura la memoria máxima según la cantidad de datos que necesites cachear.
Redis almacena datos frecuentemente consultados y reduce significativamente las consultas a la base de datos. Para módulos personalizados, usa el API de cache de Odoo con el decorador ormcache para almacenar resultados de funciones que se ejecutan frecuentemente pero rara vez cambian.
6. Compresión HTTP y Optimización de Recursos
Habilita la compresión en Nginx para reducir el tamaño de las respuestas HTTP entre un 60 y 80 por ciento, mejorando significativamente los tiempos de carga especialmente para usuarios con conexiones lentas. Configura los tipos MIME que deseas comprimir y establece un nivel de compresión equilibrado entre reducción de tamaño y consumo de CPU.
Odoo en modo producción sirve assets estáticos minificados y concatenados automáticamente. Asegúrate de que el modo debug esté desactivado para que Odoo gestione la compilación de assets de forma eficiente.
7. Optimización de Cron Jobs
Los cron jobs más costosos en Odoo incluyen la descarga de correo entrante, la limpieza de registros temporales, la conciliación bancaria automática y las alertas de stock vencido. Configura sus horarios para horas de baja actividad en la empresa para minimizar el impacto en el rendimiento del sistema durante las horas laborales.
8. Gestión de Memoria y Evitar Memory Leaks
Odoo está escrito en Python, que puede acumular memoria con el tiempo. Los workers se reciclan automáticamente gracias a limit_request, pero debes monitorear el consumo de memoria de cada proceso worker. Si detectas un crecimiento continuo de memoria sin liberación, revisa los módulos personalizados ya que los caches que no se invalidan correctamente son la causa más común de memory leaks en Odoo.
9. Optimización de la Interfaz de Usuario
Los usuarios con conexiones lentas se benefician enormemente de imágenes optimizadas. Usa formato WebP, lazy loading en imágenes de listas, y reduce el tamaño de los archivos estáticos. En templates XML, configura el widget de imagen con opciones de preview para cargar solo thumbnails en lugar de imágenes completas.
10. Balanceo de Carga con Múltiples Servidores
Para despliegues de alta disponibilidad, configura múltiples workers en diferentes servidores con un balanceador de carga usando el algoritmo least_conn. Todos los servidores deben compartir la misma base de datos PostgreSQL y el mismo almacenamiento de archivos usando NFS, Ceph o S3-compatible storage para garantizar consistencia de datos.
11. Herramientas de Profiling para Desarrolladores
Cuando optimizas módulos personalizados, necesitas herramientas de profiling específicas como cProfile para análisis de funciones y py-spy para profiling sin reiniciar el proceso. El profiling te permite identificar exactamente qué función o método consume más tiempo y memoria en cada petición.
12. Monitoreo de Base de Datos en Tiempo Real
Queries útiles para monitorear PostgreSQL en producción incluyen la consulta de sesiones activas con duración, el tamaño de las tablas más grandes, y las tablas con más dead tuples que necesitan VACUUM. Estas métricas te ayudan a identificar problemas antes de que afecten a los usuarios.
13. Script de Optimización Automática
Crea un script cron que ejecute tareas de mantenimiento periódicas: VACUUM ANALYZE de PostgreSQL, limpieza de archivos temporales de Odoo, limpieza de logs antiguos, y reinicio automático de workers si la memoria supera el 80 por ciento. Este script se ejecuta semanalmente y mantiene el sistema en condiciones óptimas.
14. Benchmarking con Herramientas Externas
Mide el rendimiento de tu despliegue con herramientas como Apache Bench o wrk para obtener métricas objetivas de requests per second y tiempo de respuesta promedio. Compara los resultados antes y después de cada optimización para medir el impacto real de los cambios realizados.
Conclusión
La optimización de rendimiento en Odoo es un proceso continuo, no un evento único. Comienza con el diagnóstico, aplica las optimizaciones de mayor impacto como PostgreSQL, workers y caching, y monitorea los resultados de forma constante. Un Odoo bien optimizado puede manejar cientos de usuarios concurrentes sin degradación significativa del rendimiento.
15. Analisis de Plan de Ejecucion de PostgreSQL
El plan de ejecucion de PostgreSQL es la herramienta mas poderosa para entender como el motor de base de datos procesa tus consultas. EXPLAIN ANALYZE ejecuta la consulta y muestra el plan real incluyendo tiempos, costos y numero de filas procesadas. Aprende a leer los planes de ejecucion para identificar cuellos de botella.
Los nodos mas importantes en un plan de ejecucion son Seq Scan (escaneo secuencial de tabla, indicativo de falta de indices), Index Scan (uso de indice, ideal), Hash Join y Merge Join (estrategias de union), y Sort (operaciones de ordenamiento que pueden ser costosas).
Cuando identificas un Seq Scan en una tabla grande, crea un indice en el campo que se esta filtrando. Los indices compuestos son ideales para consultas que filtran por multiples campos. Un indice en (partner_id, state) es mas efectivo que dos indices separados para consultas que filtran por ambos campos.
Para consultas complejas con multiples tablas, usa EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) para ver cuanta memoria y disco usa cada nodo del plan. Los nodos con alto uso de buffers indican problemas de rendimiento que pueden resolverse con indices o ajustes de configuracion.
16. Optimizacion de Vistas Lentas
Las vistas de lista lentas en Odoo son un problema comun que afecta la productividad de los usuarios. La causa mas frecuente es la carga de demasiados campos compute o campos related que ejecutan consultas SQL adicionales por cada fila visible.
Para diagnosticar vistas lentas, activa el modo debug y revisa el numero de queries SQL ejecutadas para cada peticion. Cada query adicional aumenta el tiempo de respuesta. Si una vista ejecuta mas de 10 queries, considera optimizar los campos compute o reducir el numero de campos visibles.
Los campos compute sin store=True son especialmente costosos ya que se recalculan en cada carga de la vista. Si un campo compute se usa frecuentemente en la vista de lista, activa store=True para que se guarde en la base de datos y se actualice solo cuando cambien sus dependencias.
La paginacion es fundamental para vistas con muchos registros. Odoo carga por defecto 80 registros por pagina. Si los usuarios rara vez necesitan ver mas de 100 registros, reduce este numero para mejorar los tiempos de carga.
17. Cacheo de Consultas Frecuentes
Las consultas que se ejecutan en multiples vistas y usuarios deben cachearse para reducir la carga en PostgreSQL. Odoo implementa un nivel de cache en el ORM que almacena los resultados de las consultas de busqueda durante la vida util de la peticion HTTP.
Para consultas que se repiten entre multiples peticiones, usa Redis como cache de segundo nivel. Configura la cache de Odoo en odoo.conf con el parametro redis=127.0.0.1:6379 y establece una politica de expiracion segun la frecuencia de actualizacion de los datos.
Los datos que cambian raramente como la configuracion de la empresa, las listas de precios, y los datos de los impuestos son candidatos ideales para cacheo largo. Los datos que cambian frecuentemente como los stocks o los estados de pedidos deben tener tiempos de cache mas cortos.
Invalida la cache de forma manual cuando sea necesario ejecutando odoo-bin -c odoo.conf -u modulo --stop-after-init. Este comando actualiza el modulo y regenera los archivos estaticos, incluyendo la cache de assets.
18. Benchmarking y Comparativa de Rendimiento
El benchmarking sistematico te permite medir el impacto real de cada optimizacion y comparar el rendimiento antes y despues de los cambios. Usa herramientas como Apache Bench (ab) o wrk para pruebas de carga que simulen multiples usuarios concurrentes ejecutando operaciones reales.
Para benchmarks realistas, crea scripts que repliquen los flujos de trabajo tipicos de tu empresa. Por ejemplo, un script que simule 50 usuarios creando pedidos, consultando inventario, y generando facturas simultaneamente. Mide el tiempo promedio de respuesta, el throughput (operaciones por segundo), y la tasa de errores.
Los benchmarks de base de datos son igualmente importantes. Usa pgbench para medir el rendimiento bruto de PostgreSQL con consultas tipicas de Odoo. Compara los resultados con los benchmarks de referencia para verificar que la configuracion de PostgreSQL es optima.
Documenta los resultados de cada benchmark con la fecha, la configuracion del sistema, y los parametros de la prueba. Mantene un historial de benchmarks para identificar tendencias de rendimiento a lo largo del tiempo y justificar inversiones en infraestructura.
19. Optimizacion de Consultas con CTEs
Las Common Table Expressions (CTEs) de PostgreSQL permiten escribir consultas complejas de forma mas legible y mantenible. Para consultas de Odoo que involucran multiples subconsultas, las CTEs pueden mejorar tanto la legibilidad como el rendimiento al permitir que PostgreSQL optimice el plan de ejecucion de forma mas efectiva.
Los CTEs materializados (con MATERIALIZED) fuerzan a PostgreSQL a calcular el resultado del CTE una sola vez y reutilizarlo en multiples partes de la consulta. Esto es especialmente util cuando el mismo subconjunto de datos se usa en multiples filtros o agregaciones.
Para reportes complejos que necesitan multiples agregaciones sobre los mismos datos, los CTEs evitan la ejecucion repetida de las mismas subconsultas. PostgreSQL optimiza automaticamente los CTEs no materializados para evitar la duplicacion de trabajo.
Usa CTEs recursiones para navegar jerarquias de datos como la estructura organizacional de una empresa o las categorias de productos. Las CTEs recursiones resuelven problemas que tradicionalmente requerian multiples consultas o codigo Python complejo.
20. Optimizacion de Memoria en PostgreSQL
PostgreSQL utiliza memoria de forma diferente segun las operaciones que ejecute. La memoria compartida (shared_buffers) se usa para almacenar paginas de datos en memoria y reducir accesos a disco. Para un servidor con 16 GB de RAM, configura shared_buffers a 4 GB, que es el 25% de la memoria total.
La memoria de trabajo (work_mem) se usa para operaciones de sort, hash, y merge en consultas individuales. Un valor de 64 MB permite que PostgreSQL ejecute ordenamientos y agrupaciones complejas sin usar disco. Si tienes consultas que usan multiples sort operations, multiplica work_mem por el numero de operaciones simultaneas.
La memoria de mantenimiento (maintenance_work_mem) se usa para VACUUM, CREATE INDEX, y ALTER TABLE. Un valor de 512 MB permite que PostgreSQL ejecute estas operaciones de forma eficiente sin impactar el rendimiento de las consultas de usuarios.
Monitorea el uso de memoria de PostgreSQL con pg_stat_bgwriter que muestra cuantas paginas se escribieron desde shared_buffers y cuantas se cargaron desde disco. Si el ratio de cache hits es inferior al 99%, necesitas aumentar shared_buffers o el effective_cache_size.
21. Optimizacion de Consultas de Herencia
Las consultas de herencia en Odoo usan UNION ALL para combinar registros de multiples tablas. Estas consultas pueden ser lentas cuando las tablas padre e hija tienen muchos registros. Para mejorar el rendimiento, crea indices en las foreign keys y en los campos que se usan frecuentemente en filtros.
Los modelos que usan _inherits (herencia por delegacion) generan consultas con JOIN entre la tabla padre y la tabla hija. Estos JOINs pueden ser costosos si las tablas son grandes. Considera usar _inherit en lugar de _inherits si no necesitas la flexibilidad de la herencia por delegacion.
Para modelos con multiples niveles de herencia, las consultas pueden volverse muy complejas. Odoo optimiza automaticamente las consultas de herencia, pero en casos extremos puedes crear vistas materializadas que pre-calculen los resultados de las consultas mas complejas.
Los campos related que atraviesan multiples niveles de herencia pueden causar consultas N+1. Para evitar esto, usa prefetched=True en los campos related o implementa un compute que cargue todos los datos necesarios en una sola consulta.
22. Optimizacion de la Capa de Cache
La capa de cache en Odoo opera en multiples niveles para maximizar el rendimiento. El primer nivel es el cache del ORM que almacena los resultados de las consultas de busqueda durante la vida util de la peticion HTTP. Este cache es automatico y no requiere configuracion adicional.
El segundo nivel es Redis que almacena datos que se consultan frecuentemente pero que no cambian con frecuencia. La configuracion de Redis debe equilibrar el tamano de memoria asignada con la tasa de aciertos esperada. Una memoria insuficiente causa evictions frecuentes que degradan el rendimiento.
El tercer nivel es el cache HTTP que se configura en Nginx con los headers Cache-Control. Los archivos estaticos de Odoo (CSS, JavaScript, imagenes) pueden cachearse en el navegador del cliente durante periodos prolongados ya que incluyen hashes en los nombres de archivo que cambian cuando el contenido se modifica.
Para datos que cambian periodicamente como los precios de lista o las configuraciones de empresa, implementa una estrategia de cache con invalidacion proactiva. Cuando los datos cambian, invalida la cache de Redis y envia un header de invalidacion al navegador para que descargue la version actualizada.