How I Saved 2.7GB of Memory in Odoo by Skipping the ORM
I recently needed to process 400,000 accounting lines in Odoo. While experimenting with memory profiling, I ran a benchmark on a subset of 10,000 records—and the results were eye-opening.
🧪 Benchmark Results (on 10k records)
from pympler import asizeof
# Classic ORM usage
classic = env['account.move.line'].search([], limit=10000)
classic.mapped('name') # forces read
print("Classic:", asizeof.asizeof(classic) / 1024 / 1024, "MB")
# ~70MB
env.invalidate_all()
# ORM without prefetching
light = env['account.move.line'].with_context(prefetch_fields=False).search([], limit=10000)
light.mapped('name')
print("No prefetch:", asizeof.asizeof(light) / 1024 / 1024, "MB")
# ~25MB
env.invalidate_all()
# Raw SQL via cursor
env.cr.execute("""
SELECT name FROM account_move_line
ORDER BY date DESC, move_name DESC, id
LIMIT 10000
""")
rows = env.cr.fetchall()
print("Raw tuples:", asizeof.asizeof(rows) / 1024 / 1024, "MB")
# ~1.5MB
🤔 What This Really Means
These results are not just numbers—they reveal something deeper about how Odoo loads and stores data:
The ORM is convenient, but every bit of convenience comes at a cost: memory, latency, and object complexity.
Even without prefetching, Odoo still builds full recordsets with metadata, methods, and context.
The raw SQL result (a list of tuples) is just plain data. That simplicity is what makes it powerful and memory-friendly.
When you're just reading values, especially at scale, the ORM becomes a luxury you might not need.
🧮 Extrapolated for 400,000 records
MethodEst. Memory Use (400k)CommentsClassic ORM~2.8 GBLoads related fields, expensiveNo Prefetch~1.0 GBLighter but still bulkyRaw SQL (tuples)~60 MB✅ Leanest and fastest option
That’s a 2.74GB saving with one simple change.
✅ When to Use This
You're processing hundreds of thousands of records
You don’t need ORM features (onchange, access rights, tracking)
You're doing read-only operations (exports, reports, analytics)
⚠️ Caveats
You lose the power of fields and record methods
You’re responsible for data validation and types
It’s not suitable when modifying or creating records
🧠 Final Thoughts
You don’t always need to go lower-level.But when you do—the gains can be massive.
This is a reminder that ORMs are abstraction layers, not magic. When you know what’s under the hood, you can choose the right tool for each job.
Whether you're building an export, a batch job, or a one-off script—be mindful of memory. It might just save you from crashes, slowdowns, and server pain.
If you enjoyed this insight, drop a comment or share your own optimization tricks!
Top comments (0)