Odoo Performance Optimization After Migration: Why Your Upgrade Got Slower, and How to Fix It
The real causes are stale stats, missing indexes and dev mode left on. A post-migration fix sequence from ERP360’s UAE team.
You migrated to a newer Odoo version expecting it to run faster, and instead the Sales list crawls and reports time out — common, and fixable. Odoo performance optimization after a migration is a different job from generic speed tuning, because a migration introduces its own specific causes that ordinary tuning never addresses.
TL;DR Post-migration slowness usually comes from stale database statistics, indexes the upgrade did not recreate, –dev/threaded mode left on from testing, and ported custom code carrying old patterns. Run ANALYZE first, confirm multiprocessing is on, verify your indexes survived, then profile the modules that changed. Only after that do you reach for general PostgreSQL and worker tuning.
Odoo Slow After Migration: Why the Upgrade Regressed
When your Odoo is slow after migration, the instinct is to blame the new version or the server. Usually it is neither. A migration changes the database structure, the code, and sometimes the host, and each of those carries a performance side effect that a fresh install never has. Effective Odoo performance optimization starts by naming these causes, because they are distinct from the general “my Odoo is slow” list every tuning guide already covers.
The recurring culprits, roughly in order of how often they cause a post-migration regression:
- Stale PostgreSQL statistics. The migration loads large volumes of data, but the query planner’s statistics do not refresh automatically at the moment you go live. Until they do, the planner works from out-of-date row estimates and picks bad plans — the single most common quiet cause of “it was fine before the upgrade.”
- Indexes that were not recreated. Migration tooling rebuilds the schema, but custom indexes you added by hand to the old database, and occasionally standard ones, do not always survive the transfer. A query that used an index scan yesterday falls back to a sequential scan today.
- Development or threaded mode left running. Teams test a migration with –dev enabled or in single-process threaded mode, confirm it works, and push it live without switching back to multiprocessing workers. Odoo’s own community threads flag this repeatedly. It is the highest-impact, lowest-effort fix on this list.
- Ported custom modules carrying old patterns. Custom code moved from an older version often keeps deprecated ORM patterns, stored computed fields that now recompute more aggressively, or logic that assumes a behaviour the new version changed. It ran acceptably before; on the new version it does not.
- Bloat migrated wholesale. Heavy tables like ir_attachment and mail_message come across in full, including years of accumulated weight you never pruned. You inherited the old database’s neglect.
- Genuinely changed behaviour between versions. Some views, ORM methods, and defaults simply work differently across versions. This is real, but it is the last thing to suspect, not the first.
If those custom modules are the suspect, our Odoo customization team sees the same deprecated patterns repeatedly after an upgrade.
Diagnose Before You Tune: Find the Real Bottleneck
The mistake that costs the most time is tuning blind. Odoo performance issues after upgrade look identical on the surface — everything feels slow — but the cause could be the database, the application layer, the worker configuration, or the network. Guessing wastes days, so Odoo performance optimization begins with measurement, not settings.
Three tools give you the whole picture:
- The Odoo Profiler (Developer Tools → Performance) shows which methods and queries a slow page actually spends its time in. Start here, on the specific screen users complain about.
- PostgreSQL’s pg_stat_statements ranks your queries by total time consumed, so you see which statements are genuinely expensive rather than which ones feel slow.
- EXPLAIN (ANALYZE, BUFFERS) on the worst offenders tells you whether a query is doing a sequential scan it should not, and whether an index would actually help before you add one.
Run these against a baseline comparison wherever you can. If you capture timings before the migration, the gap between then and now points straight at what the migration changed, rather than at every theoretically-slow thing in the stack.
The Post-Migration Fix Sequence
Here is how to speed up Odoo after a migration in the order that resolves the most pain for the least effort. This Odoo performance optimization sequence is deliberately different from a generic checklist, because it front-loads the causes specific to having just migrated.
Step 1 — Refresh statistics with ANALYZE
Run VACUUM ANALYZE across the migrated database, or at minimum ANALYZE, before you change anything else. This updates the planner’s statistics against the freshly loaded data and, on its own, resolves a large share of post-migration slowdowns. It is fast, safe, and changes no data, only the planner’s knowledge of it.
Step 2 — Confirm multiprocessing is on
Verify the instance is running with –workers set for production, not in –dev or single-process threaded mode. In threaded mode Odoo handles one request at a time; a busy team queues behind it and every screen feels slow regardless of how well the database is tuned. This is the fix most likely to have been skipped, and the fastest to apply.
Step 3 — Verify your indexes survived
Check that the custom indexes from your old database exist on the new one, and re-create any that did not transfer. Use the slow-query ranking from your diagnosis to confirm the hot tables are indexed on the columns your reports and filters actually use.
Step 4 — Profile the modules that changed most
Migrations most often regress the modules that saw the biggest version jump — community threads repeatedly cite Sales and Inventory. Point the Profiler at those first, and at any custom module you ported, before you assume the platform itself is the problem.

Running ANALYZE and confirming multiprocessing workers resolves most post-migration slowdowns before any deeper tuning is needed.
Odoo PostgreSQL Performance Tuning
Once the migration-specific causes are cleared, general database tuning carries you the rest of the way — Odoo runs on PostgreSQL, and its defaults are conservative on purpose. Database tuning is the core of Odoo performance optimization once the migration debris is gone, and effective Odoo PostgreSQL performance tuning starts with four settings, sized to your server rather than copied from a blog:
- shared_buffers — roughly a quarter of server RAM. Going far higher rarely helps, because PostgreSQL also leans on the operating system’s page cache.
- effective_cache_size — set to reflect the memory available for caching, so the planner knows how much of the database is likely already in memory.
- work_mem — tuned to your concurrency; too high multiplied across many workers exhausts RAM, too low forces sorts to disk.
- random_page_cost — lowered toward 1.1 when the database is on SSD or NVMe, so the planner stops over-penalising index scans.
Two further levers matter at scale. Add indexes only when EXPLAIN (ANALYZE, BUFFERS) proves they remove a scan or an expensive sort — every extra index slows writes and adds autovacuum work. And when many workers open more connections than PostgreSQL should hold, put PgBouncer in transaction-pooling mode in front of the database; it is connection control, not a magic speed switch, but it prevents connection exhaustion from masquerading as slowness. This database-layer work is a core part of managed Odoo support for a live instance.
Odoo Worker Configuration and Server Sizing
Getting your Odoo worker configuration right is the other half of the equation, and it depends on your CPU, your RAM, and how many people use the system at once. The widely-used starting point for worker count is (CPU cores × 2) + 1, adjusted from there: if the system feels sluggish while CPU stays comfortably under load and RAM is free, add a worker; if workers are being killed for exceeding memory, you have too many or the memory limits are set too high.
Size RAM to the workers, not the other way round. A rough sizing is (workers × hard memory limit) + PostgreSQL memory + operating-system overhead, and it is easy to configure more workers than the server can actually feed. Set the soft and hard memory limits in odoo.conf so a single runaway request is recycled rather than allowed to starve everything else.
Keep the database on SSD or NVMe — PostgreSQL is disk-I/O-bound for Odoo’s workloads, so fast storage buys more than raw CPU does. Getting this right is part of a clean Odoo implementation, migration or not.
| Symptom | Most likely layer | First move |
|---|---|---|
| Slow immediately after go-live, was fine before | Stale statistics | VACUUM ANALYZE |
| Everything queues under light load | Threaded/dev mode left on | Enable –workers |
| One report or list view is slow, rest is fine | Missing index / bad query | Profile, then EXPLAIN ANALYZE |
| Workers killed, requests fail intermittently | Memory limits vs worker count | Rebalance workers and RAM |
| Gradual slowdown over months | Database bloat / data growth | Cleanup, then re-tune |
Custom Modules and ORM Code After Migration
Ported customisations are where post-migration slowness hides longest, because the code runs — it is just heavier than it was. Review the modules you carried across for a few specific things: ORM calls that loop where a batched read or write would do, computed fields that are stored and now recompute on more triggers than intended, and any place raw logic assumed an older version’s behaviour. For large data operations, a batched operation or carefully-scoped SQL often beats looping through the ORM record by record, and pagination on heavy list and report queries keeps result sets from ballooning.
This is exactly the kind of work our team handles when a client comes to ERP360 after an upgrade that left their instance slower than the version they left behind — the fix is usually in the ported code and the database, not in the platform. Deeper cases go to our Odoo software development team.
Database Cleanup and Odoo Database Optimization
Effective Odoo database optimization after a migration means clearing the weight you brought across rather than tuning around it. The ir_attachment and mail_message tables are the usual offenders — years of attachments, tracked-message history, and logged changes that were never pruned.
Schedule a regular VACUUM ANALYZE for low-traffic windows to reclaim space and keep statistics fresh, and consider more frequent maintenance on the heaviest tables. Uninstall modules the business no longer uses; every installed app adds tables, cron jobs, and overhead whether or not anyone touches it. A leaner database is faster to query and cheaper to back up.
When It Is Not the Migration
Not every post-migration slowdown is a migration defect, and pretending otherwise sends you chasing a ghost. Before you conclude your Odoo performance optimization work has failed, weigh two honest possibilities:
- You have more data now. If months passed between the old baseline and the migration, transaction volume grew. The system may be slower because it is doing more, not because the upgrade broke something. Compare like-for-like data volumes before blaming the migration.
- The new version is genuinely heavier in places. Some releases add features that cost cycles. That is a capacity conversation — more resources or tighter configuration — not a bug hunt.
The way to tell the difference is the baseline comparison from the diagnosis step. If a specific screen that was fast is now slow on the same data, that is a migration effect worth fixing. If everything is uniformly a little heavier and your data has doubled, that is growth, and the answer is capacity.
Hosting and Latency for UAE Deployments
Where you host after a migration is a performance decision, not just a cost one, and for UAE businesses it carries two extra considerations. Latency to your users: if your team is in the Emirates but the instance sits in a distant default region, every request pays a round-trip tax that no amount of database tuning removes; hosting closer to your users is sometimes the biggest single win available. Data-residency expectations: UAE businesses in regulated sectors often have views on where operational data physically lives, which narrows the hosting choices worth considering.
These are business decisions as much as technical ones, and the honest position is that the right answer depends on your user base and your sector rather than on a universal rule. Shared Odoo hosting adds a wrinkle: on shared infrastructure your performance depends partly on other tenants and on worker limits you cannot change, which is worth weighing when a migration is also a chance to move host.
Keeping Odoo Fast: Ongoing Maintenance
Odoo performance optimization is not a one-time event — it decays as data grows and usage patterns shift. Build a light routine: schedule VACUUM ANALYZE for off-peak hours, watch your slow-query ranking and cache-hit ratio so regressions surface before users complain, keep an eye on worker memory, and revisit configuration when headcount or transaction volume steps up. A migration is the natural moment to establish this cadence, because you have just paid the price of neglecting it. If you would rather hand it off, talk to ERP360 about a maintenance plan.
Frequently Asked Questions
Q: Why is Odoo slow after a migration when it was fine before?
Because a migration introduces causes a stable instance does not have: stale query-planner statistics, indexes that did not transfer, development or threaded mode left on from testing, and ported custom code carrying old patterns. Start by running ANALYZE, confirming multiprocessing workers are enabled, and verifying your indexes survived — that clears most cases before you touch general tuning.
Q: What makes Odoo slow in general, migration aside?
Common causes are conservative default PostgreSQL settings, too few or too many workers, missing indexes on hot tables, a bloated database, insufficient RAM or slow storage, and heavy custom modules. Diagnose with the Odoo Profiler and pg_stat_statements before changing settings, so you fix the actual bottleneck rather than guessing.
Q: How do I do Odoo speed optimization without a developer?
Several high-impact moves need no code: run VACUUM ANALYZE, enable multiprocessing workers, tune the core PostgreSQL settings to your server size, move the database to SSD, and uninstall unused modules. The code-level work — reviewing ported custom modules and rewriting inefficient ORM logic — does need a developer, and it is usually where the deepest post-migration gains sit.
Q: How long should performance tuning take after a migration?
The migration-specific fixes — statistics, worker mode, index checks — are typically quick and deliver the largest immediate improvement. Deeper database tuning and custom-code review take longer and are best done against measurements rather than by trial and error. Diagnosing properly first is what keeps post-migration Odoo performance optimization from dragging on.
The Bottom Line
Odoo performance optimization after a migration is a specific job, not a generic one. The slowness you are seeing usually traces to stale statistics, un-recreated indexes, worker mode left in a testing state, or ported code carrying old habits — causes a fresh install never has. Work the post-migration sequence first, diagnose before you tune, and be honest about when the real story is simply more data.
If your instance is slower after an upgrade and you would rather not chase it yourself, ERP360’s Odoo upgrade and migration team does exactly this work for UAE businesses. Talk to ERP360 about a post-migration performance review.
Is Your Odoo Instance Slower After an Upgrade?
ERP360’s UAE team runs the full post-migration diagnostic — statistics, indexes, worker mode and ported code — and fixes what’s actually causing it.
Request a Performance Review

