Skip to content

Odoo Slow? How to Diagnose and Fix Performance Issues

DeployMonkey Team · March 11, 2026 10 min read

Slow Odoo performance is almost always caused by one of four things: misconfigured worker counts, unindexed or inefficient PostgreSQL queries, excessive installed modules loading unnecessary Python code, or hardware bottlenecks (disk I/O, CPU saturation). Working through a structured checklist is far faster than guessing.

Why Odoo Gets Slow

Odoo is a large Python application that talks to PostgreSQL for every meaningful operation. Performance problems compound quickly: a slow database query stalls a worker thread, which queues other requests, which makes the whole interface feel sluggish. Understanding which layer is slow is the first and most important step.

The major slowness categories are:

  • Worker starvation — too few workers for the concurrent load
  • Database bottleneck — slow queries, missing indexes, bloated tables
  • Disk I/O — slow storage for the PostgreSQL data directory, especially on shared VPS hosting
  • Memory pressure — workers swapping to disk (see Fix Odoo Out of Memory Error)
  • Module bloat — hundreds of modules installed, slowing Python import time and adding computed fields to every query
  • Large attachments — filestore stored in the database rather than on disk

Diagnostic Checklist

Step 1: Check Server Resources

# CPU and load average
top -b -n 1 | head -5
# or use htop for interactive view
htop

# Memory
free -h

# Disk I/O — is PostgreSQL's data dir on a slow disk?
iostat -x 1 5
df -h

# Are Odoo workers near their memory limits?
ps aux --sort=-%mem | grep "[o]doo"

If load average consistently exceeds the number of CPU cores, you have a CPU bottleneck. If swap usage is non-zero during normal operation, you have a memory shortage. If iowait in iostat is above 20%, disk I/O is the bottleneck.

Step 2: Identify Slow PostgreSQL Queries

-- Connect to your Odoo database
psql -U odoo -d mydb

-- Find currently running queries longer than 5 seconds
SELECT pid, now() - pg_stat_activity.query_start AS duration, query, state
FROM pg_stat_activity
WHERE state != 'idle'
  AND (now() - pg_stat_activity.query_start) > interval '5 seconds'
ORDER BY duration DESC;

-- Find the slowest queries overall (requires pg_stat_statements)
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;

Once you have a slow query, use EXPLAIN ANALYZE to understand its execution plan:

EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM sale_order WHERE partner_id = 42 ORDER BY date_order DESC LIMIT 20;

Look for Seq Scan on large tables — these are full table scans that indicate a missing index. See How to Optimize PostgreSQL for Odoo for indexing strategies.

Step 3: Enable Odoo's Built-in Profiler

Odoo 16+ ships with a built-in profiler accessible from the debug menu. Enable developer mode (?debug=1 in the URL), then go to Settings → Technical → Performance → Enable Profiling. This records a flamegraph of Python call time and SQL queries for any page load.

# For Odoo 14/15, enable SQL logging in odoo.conf for ad-hoc diagnosis
# WARNING: extremely verbose — disable immediately after
log_level = debug_sql

Step 4: Check Module Count

-- Count installed modules
SELECT COUNT(*) FROM ir_module_module WHERE state = 'installed';

-- List modules by category
SELECT category_id, COUNT(*) FROM ir_module_module
WHERE state = 'installed'
GROUP BY category_id ORDER BY count DESC;

A standard Odoo install has 50–80 modules. Instances with 200+ modules will be noticeably slower on every page load due to increased ORM overhead, more computed fields to evaluate, and slower Python import chains. Audit installed modules and remove anything not actively used.

Step 5: Check for Large Attachments in the Database

-- Find large attachments stored as database blobs (not on disk)
SELECT name, mimetype, pg_size_pretty(length(db_datas)) AS size
FROM ir_attachment
WHERE db_datas IS NOT NULL
ORDER BY length(db_datas) DESC
LIMIT 20;

If you see large files (images, PDFs) stored in the database, switch Odoo's filestore to disk-based storage by setting data_dir in odoo.conf and running ir.attachment._force_write_image_attachment_to_filestore() via the Odoo shell.

Step 6: Review Odoo Logs for Slow Requests

# Find requests that took longer than 1 second
grep "TIME" /var/log/odoo/odoo.log | awk '$NF > 1000' | sort -k NF -n | tail -20

# Find exceptions and errors
grep -E "ERROR|WARNING|Traceback" /var/log/odoo/odoo.log | tail -50

Common Culprits and Quick Fixes

SymptomLikely CauseQuick Fix
All pages slowWorker starvation or DB bottleneckIncrease workers; check pg_stat_activity
One page slowSpecific query missing indexEXPLAIN ANALYZE + add index
Slow after module installNew computed fields added to hot tablesProfile with debug_sql; consider removing module
Slow file uploads/downloadsAttachments stored in DBMove filestore to disk
Slow after some hoursMemory leak / table bloatSet limit_memory_soft; run VACUUM ANALYZE
Slow reports onlyHeavy PDF generationIncrease limit_time_real; use background jobs for bulk reports

How DeployMonkey Handles Performance

DeployMonkey provisions every Odoo instance with a performance baseline: PostgreSQL is deployed with tuned shared_buffers, work_mem, and effective_cache_size values sized for the server's RAM. Workers are pre-configured using the (2×CPU)+1 formula. SSD-backed block storage is used for all PostgreSQL data directories — no spinning disks.

The monitoring dashboard surfaces response time percentiles (p50, p95, p99) per instance so you can see exactly when performance degraded and correlate it with deployments, cron job runs, or traffic spikes. Long-running PostgreSQL queries are flagged automatically when they exceed a configurable threshold.

For Agency plan customers, DeployMonkey includes a query advisor that identifies tables lacking indexes in your specific Odoo database schema — accounting for which modules you have installed — rather than relying on generic recommendations that may not apply to your instance.

Related Articles

Frequently Asked Questions

Why is Odoo slow only for some users but not others?

This usually indicates worker starvation during peak hours. Some users' requests land on a free worker instantly while others queue. Check your worker count versus concurrent active users and increase workers if needed.

Does Odoo Community perform worse than Enterprise?

No — the performance characteristics of the core framework are identical. Enterprise adds more modules and features, which means more installed modules and potentially more computed fields. A lean Enterprise install with only needed modules can outperform a bloated Community install.

How do I identify which custom module is causing slowness?

Enable Odoo's profiler (Settings → Technical → Performance → Enable Profiling in debug mode) and load the slow page. The flamegraph will show you which Python functions and SQL queries consume the most time, making it straightforward to trace back to a specific module.

What is a healthy Odoo page load time?

A well-tuned Odoo instance should load most list and form views in under 500 ms for logged-in users. Dashboard pages with complex groupings can take 1–2 seconds. Anything consistently above 3 seconds warrants investigation.

Can enabling the Odoo cache improve performance?

Odoo uses an in-process LRU cache (the ORM cache) automatically. For high-traffic deployments, adding a Redis cache for session storage reduces database pressure. DeployMonkey's Pro and Agency plans support Redis session backends out of the box.

Get a Fast Odoo Instance Without the Tuning Work

DeployMonkey deploys Odoo with production-ready performance settings pre-applied: tuned PostgreSQL, optimised worker config, SSD storage, and real-time monitoring.

Start Free — No Credit Card Required