Fait partie de notre série Performance & Scalability
Lire le guide completOdoo Performance Tuning : PostgreSQL et optimisation du serveur
Une instance Odoo lente coûte de l’argent en perte de productivité et en utilisateurs frustrés. La bonne nouvelle : la plupart des problèmes de performances d’Odoo peuvent être résolus sans mise à niveau matérielle. La mauvaise nouvelle : diagnostiquer la cause première nécessite de comprendre l’ensemble de la pile : Python, PostgreSQL, Nginx, Redis et la couche réseau.
Ce guide couvre le cycle de vie complet d'optimisation des performances pour Odoo 19 Enterprise : identification des goulots d'étranglement, réglage de PostgreSQL, optimisation des paramètres du serveur Odoo, configuration de la mise en cache Nginx et dimensionnement approprié de votre infrastructure en fonction de votre nombre d'utilisateurs et de votre volume de transactions.
Points clés à retenir
- Le réglage PostgreSQL offre les gains de performances les plus importants (50 à 300 % dans les installations typiques)
- Les tampons partagés doivent être définis à 25 % de la RAM disponible comme point de départ
- L'ORM d'Odoo génère N+1 requêtes qui peuvent être interceptées avec pg_stat_statements
- Les index sur les champs fréquemment filtrés (company_id, state, date) sont obligatoires
- La mise en cache du proxy Nginx sert les actifs statiques sans toucher le serveur Odoo
- La configuration des travailleurs a un impact direct sur la capacité des utilisateurs simultanés
- La mise en cache de session Redis réduit la charge de la base de données pour l'authentification
- Les plannings d'aspiration et d'analyse doivent être adaptés aux charges de travail Odoo à forte écriture
Diagnostiquer les goulots d'étranglement des performances
Avant de régler quoi que ce soit, identifiez où le temps est réellement passé. L’optimisation aveugle gaspille des efforts.
Activer la journalisation des requêtes Odoo :
# odoo.conf
[options]
log_level = info
logfile = /var/log/odoo/odoo.log
# For SQL query logging (development/staging only):
log_handler = odoo.sql_db:DEBUG
Activer la journalisation lente des requêtes PostgreSQL :
# /etc/postgresql/15/main/postgresql.conf
log_min_duration_statement = 1000 # Log queries taking > 1 second
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_connections = on
log_lock_waits = on
Installez pg_stat_statements (extension PostgreSQL la plus précieuse) :
-- Enable the extension
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Find the top 20 slowest queries
SELECT
round(total_exec_time::numeric, 2) AS total_ms,
calls,
round(mean_exec_time::numeric, 2) AS mean_ms,
round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 2) AS pct,
left(query, 100) AS query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
-- Reset statistics after tuning to measure improvement
SELECT pg_stat_statements_reset();
Identifier les requêtes N+1 dans Odoo :
Les requêtes N+1 se produisent lorsqu'Odoo charge une liste d'enregistrements, puis effectue une requête par enregistrement pour récupérer les données associées. Recherchez des modèles comme celui-ci dans pg_stat_statements :
-- This query appearing 500 times in a single page load = N+1 problem
SELECT * FROM res_partner WHERE id = $1
Le correctif consiste à utiliser le mécanisme prefetch_ids d'Odoo ou à ajouter select à votre requête ORM :
# Bad: triggers N+1 for partner on each order
for order in orders:
print(order.partner_id.name) # One query per order
# Good: prefetch partner data in one query
orders = self.env['sale.order'].search([...])
orders.mapped('partner_id') # Forces prefetch
for order in orders:
print(order.partner_id.name) # No additional queries
Réglage de la configuration PostgreSQL
PostgreSQL est livré avec des valeurs par défaut conservatrices conçues pour fonctionner sur n'importe quel matériel. Pour un serveur de production Odoo, ces valeurs par défaut doivent être ajustées.
Paramètres de mémoire (pour un serveur de 32 Go de RAM) :
# /etc/postgresql/15/main/postgresql.conf
# Shared buffers: 25% of RAM
shared_buffers = 8GB
# Work memory: per-operation memory for sorts/joins
# Start conservative, increase if you see disk sorts
work_mem = 64MB
# Maintenance work memory: for VACUUM, CREATE INDEX
maintenance_work_mem = 2GB
# Effective cache size: tells planner how much OS cache is available
# Set to 75% of total RAM
effective_cache_size = 24GB
# WAL settings for better write performance
wal_buffers = 256MB
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min
max_wal_size = 4GB
min_wal_size = 1GB
Paramètres de connexion :
# Maximum connections (Odoo workers × 2 + headroom)
max_connections = 200
# For connection pooling with PgBouncer
# If using PgBouncer, reduce to 50-100
Paramètres du planificateur de requêtes :
# Enable parallel query execution
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
max_worker_processes = 16
# SSD storage: random_page_cost should equal seq_page_cost
random_page_cost = 1.1 # Default is 4.0 (for spinning disk)
seq_page_cost = 1.0
# Increase statistics target for better query plans on Odoo's large tables
default_statistics_target = 200
Réglage automatique du vide pour les charges de travail à écriture élevée :
Les modules d'inventaire, de comptabilité et de messagerie d'Odoo génèrent un trafic INSERT/UPDATE important. Les paramètres d'autovide par défaut sont insuffisants :
autovacuum = on
autovacuum_max_workers = 5
autovacuum_naptime = 30s
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
autovacuum_vacuum_scale_factor = 0.01 # Vacuum when 1% of rows are dead
autovacuum_analyze_scale_factor = 0.005 # Analyze when 0.5% of rows change
autovacuum_vacuum_cost_delay = 2ms # Reduce I/O throttling
Index de bases de données critiques
Les index manquants sont la deuxième cause la plus courante de problèmes de performances d'Odoo après une mauvaise configuration. Odoo crée des index pour les clés primaires et certaines clés étrangères, mais de nombreux champs couramment filtrés manquent d'index.
Vérifiez les index manquants à l'aide de la vue pg_missing_fk_indexes :
-- Find foreign keys without indexes
SELECT
tc.table_name,
kcu.column_name,
ccu.table_name AS foreign_table_name,
pg_relation_size(tc.table_name::regclass) AS table_size
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu
ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY'
AND NOT EXISTS (
SELECT 1 FROM pg_indexes pi
WHERE pi.tablename = tc.table_name
AND pi.indexdef LIKE '%' || kcu.column_name || '%'
)
ORDER BY table_size DESC;
Index essentiels pour Odoo 19 :
-- Sale orders (most queried table)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_state
ON sale_order(state);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_company_date
ON sale_order(company_id, date_order DESC);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_partner
ON sale_order(partner_id) WHERE state != 'cancel';
-- Account moves (invoicing)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_state_type
ON account_move(state, move_type);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_company_date
ON account_move(company_id, invoice_date DESC);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_partner
ON account_move(partner_id) WHERE state = 'posted';
-- Account move lines (most queried for reconciliation)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_line_account_reconcile
ON account_move_line(account_id, reconciled, date);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_line_move_date
ON account_move_line(move_id, date);
-- Stock moves (inventory)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_stock_move_state_product
ON stock_move(state, product_id);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_stock_quant_product_location
ON stock_quant(product_id, location_id);
-- Mail messages (can grow very large)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_mail_message_res_model_id
ON mail_message(res_model, res_id);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_mail_message_date
ON mail_message(date DESC);
-- IR rule performance (access control)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_ir_rule_model_groups
ON ir_rule(model_id);
Configuration du travailleur Odoo
Le nombre de travailleurs Odoo détermine le nombre de requêtes simultanées que le serveur peut gérer.
Formule pour le nombre de travailleurs :
Workers = (CPU_cores × 2) + 1
Memory per worker: 256MB - 512MB depending on workload
Example for 8 CPU cores, 32GB RAM:
Workers = (8 × 2) + 1 = 17
Memory check: 17 × 512MB = 8.5GB (well within 32GB)
Paramètres du travailleur odoo.conf :
[options]
# Worker processes
workers = 17
# Limits to prevent runaway workers
limit_memory_hard = 2684354560 # 2.5GB hard limit (kills worker)
limit_memory_soft = 2147483648 # 2GB soft limit (triggers gc)
limit_time_cpu = 600 # CPU seconds per request
limit_time_real = 1200 # Wall clock seconds per request
limit_request = 8192 # Requests before worker restart
# Long polling (for live notifications)
longpolling_port = 8072
Comprendre les types de travailleurs :
Odoo utilise deux types de travailleurs :
- Travailleurs HTTP (configuration
workers) : gérer toutes les requêtes Web - Cron Workers (1 réservé) : exécutez les actions planifiées en arrière-plan
Le travailleur cron est toujours en cours d'exécution mais ne compte pas dans votre capacité HTTP. Assurez-vous qu’au moins 1 travailleur cron est disponible même en cas de charge de pointe.
Configuration Nginx pour les performances
Nginx se trouve devant Odoo et gère la terminaison TLS, le service de fichiers statiques et éventuellement la mise en cache.
Configuration Nginx hautes performances :
upstream odoo {
server 127.0.0.1:8069 weight=1 fail_timeout=0;
}
upstream odoochat {
server 127.0.0.1:8072 weight=1 fail_timeout=0;
}
# Cache zone for static assets
proxy_cache_path /var/cache/nginx/odoo
levels=1:2
keys_zone=odoo_cache:100m
max_size=1g
inactive=60m
use_temp_path=off;
server {
listen 443 ssl http2;
server_name your-odoo.com;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
gzip_comp_level 6;
# Static file caching
location /web/static/ {
proxy_cache odoo_cache;
proxy_cache_valid 200 7d;
proxy_cache_use_stale error timeout updating
http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status;
expires 7d;
proxy_pass http://odoo;
}
# Long polling for live chat/notifications
location /web/longpolling {
proxy_pass http://odoochat;
proxy_read_timeout 3600s;
proxy_connect_timeout 300s;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Main application
location / {
proxy_pass http://odoo;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 720s;
proxy_connect_timeout 300s;
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy strict-origin-when-cross-origin;
}
}
Redis pour la session et le cache
Redis réduit considérablement la charge de la base de données pour la gestion des sessions et le cache ORM d'Odoo.
Installer et configurer Redis :
# Install Redis
sudo apt install redis-server
# Configure Redis for Odoo (max 4GB memory, LRU eviction)
sudo nano /etc/redis/redis.conf
# redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru
save "" # Disable persistence for pure cache
tcp-keepalive 300
Configurez Odoo pour utiliser Redis :
# odoo.conf
[options]
# Redis for session storage
session_redis_host = 127.0.0.1
session_redis_port = 6379
session_redis_prefix = odoo_session_
# Redis for IR rules and ORM cache
cache_redis_host = 127.0.0.1
cache_redis_port = 6379
Surveillance et gestion continue des performances
Configurez pgBadger pour l'analyse des journaux PostgreSQL :
# Install pgBadger
sudo apt install pgbadger
# Generate report from PostgreSQL logs
pgbadger /var/log/postgresql/postgresql-15-main.log \
-o /var/www/html/pgbadger/index.html \
--format html \
--top 20
Mesures clés à surveiller :
| Métrique | Seuil d'avertissement | Seuil critique |
|---|---|---|
| Temps de chargement des pages | > 2 secondes | > 5 secondes |
| Temps de requête de base de données | > 100 ms en moyenne | > 500 ms en moyenne |
| Mémoire du travailleur | > 80 % de la limite | > 95 % de la limite |
| Connexions PostgreSQL | > 70% du maximum | > 90 % du maximum |
| IOPS disque | > 80 % du provisionné | > 95 % du provisionné |
| Taux de réussite du cache | <95% | < 90 % |
Questions fréquemment posées
Quelle est la spécification minimale du serveur pour 50 utilisateurs Odoo simultanés ?
Pour 50 utilisateurs simultanés avec un volume de transactions modéré : 8 vCPU, 32 Go de RAM, 500 Go de SSD (NVMe de préférence). La base de données PostgreSQL d'Odoo constitue le principal goulot d'étranglement des E/S, donc un stockage rapide compte plus que la vitesse brute du processeur. Configurez 13 travailleurs (8 × 2-3 pour la marge), 8 Go de tampons partagés et assurez-vous que votre base de données se trouve sur le volume SSD.
Comment puis-je diagnostiquer si ma lenteur Odoo est Python ou PostgreSQL ?
Utilisez le profileur intégré d'Odoo (Paramètres → Technique → Performance → Profileur en mode développeur) pour enregistrer une opération lente. Le flamegraph indiquera si du temps est passé dans le code Python ou en attente des résultats SQL. Si les requêtes SQL dominent, concentrez-vous sur le réglage et les index de PostgreSQL. Si Python domine, recherchez la mise en cache @api.depends manquante ou les inefficacités du code personnalisé.
Dois-je utiliser PgBouncer pour le regroupement de connexions ?
Oui, pour les déploiements avec plus de 30 travailleurs Odoo ou un trafic API important. PgBouncer dans le pooling en mode transaction permet à de nombreux travailleurs Odoo de partager un plus petit pool de connexions PostgreSQL réelles, réduisant ainsi la surcharge par connexion. Configurez max_connections dans PostgreSQL sur 50-100 lorsque vous utilisez PgBouncer, puis définissez pool_size de PgBouncer pour qu'il corresponde à votre nombre de travailleurs Odoo.
À quelle fréquence dois-je exécuter VACUUM ANALYZE sur une base de données Odoo ?
Autovacuum gère cela automatiquement s’il est configuré correctement. Après les réglages ci-dessus (facteurs d'échelle agressifs, plus de travailleurs), l'autovacuum devrait fonctionner en continu sur les tables actives. Exécutez SELECT schemaname, tablename, last_vacuum, last_autovacuum, last_analyze, last_autoanalyze FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20; pour vérifier que les tables sont fréquemment nettoyées.
Quel est l'impact d'un trop grand nombre de travailleurs Odoo ?
Chaque travailleur Odoo consomme au minimum 256 à 512 Mo de RAM. Un trop grand nombre de nœuds de calcul entraîne un épuisement de la mémoire, provoquant un crash des nœuds de calcul (limit_memory_hard), ce qui entraîne des erreurs HTTP 500 pour les utilisateurs. De plus, un trop grand nombre de connexions PostgreSQL (workers × max_db_connections) peut surcharger la base de données. Commencez par la formule (CPU × 2 + 1), surveillez la mémoire sous charge et ajustez-la si nécessaire.
Prochaines étapes
Le réglage des performances d'Odoo est un processus itératif. Une seule session de réglage permet des gains significatifs, mais des performances durables nécessitent une surveillance continue, une analyse périodique des index et des ajustements de configuration à mesure que votre volume de données augmente.
ECOSIRE fournit des audits de performances Odoo pour les déploiements d'entreprise, identifiant les optimisations à plus fort impact pour votre charge de travail, vos modèles de transactions et votre infrastructure spécifiques. Nos ingénieurs ont optimisé les installations Odoo, depuis les PME de 10 utilisateurs jusqu'aux déploiements d'entreprise de 500 utilisateurs.
Demander un audit de performance Odoo auprès d'ECOSIRE →
Partagez les spécifications actuelles de votre serveur, le nombre d'utilisateurs et les symptômes que vous rencontrez, et notre équipe identifiera les causes profondes et vous proposera un plan d'optimisation hiérarchisé.
Rédigé par
ECOSIRE Research and Development Team
Création de produits numériques de niveau entreprise chez ECOSIRE. Partage d'analyses sur les intégrations Odoo, l'automatisation e-commerce et les solutions d'entreprise propulsées par l'IA.
Articles connexes
Odoo Accounting vs QuickBooks: Detailed Comparison 2026
In-depth 2026 comparison of Odoo Accounting vs QuickBooks covering features, pricing, integrations, scalability, and which platform fits your business needs.
Case Study: eCommerce Migration to Shopify with Odoo Backend
How a fashion retailer migrated from WooCommerce to Shopify and connected it to Odoo ERP, cutting order fulfillment time by 71% and growing revenue 43%.
Case Study: Manufacturing ERP Implementation with Odoo 19
How a Pakistani auto-parts manufacturer cut order processing time by 68% and reduced inventory variance to under 2% with ECOSIRE's Odoo 19 implementation.
Plus de Performance & Scalability
k6 Load Testing: Stress-Test Your APIs Before Launch
Master k6 load testing for Node.js APIs. Covers virtual user ramp-ups, thresholds, scenarios, HTTP/2, WebSocket testing, Grafana dashboards, and CI integration patterns.
Nginx Production Configuration: SSL, Caching, and Security
Nginx production configuration guide: SSL termination, HTTP/2, caching headers, security headers, rate limiting, reverse proxy setup, and Cloudflare integration patterns.
Odoo vs Acumatica: Cloud ERP for Growing Businesses
Odoo vs Acumatica compared for 2026: unique pricing models, scalability, manufacturing depth, and which cloud ERP fits your growth trajectory.
Testing and Monitoring AI Agents in Production
A complete guide to testing and monitoring AI agents in production environments. Covers evaluation frameworks, observability, drift detection, and incident response for OpenClaw deployments.
Compliance Monitoring Agents with OpenClaw
Deploy OpenClaw AI agents for continuous compliance monitoring. Automate regulatory checks, policy enforcement, audit trail generation, and compliance reporting.
Optimizing AI Agent Costs: Token Usage and Caching
Practical strategies for reducing AI agent operational costs through token optimization, caching, model routing, and usage monitoring. Real savings from production OpenClaw deployments.