Mina Adel
العربية Book a call
All work Fixing slow systems

Staff had accepted the system was slow. It wasn't — it was fixable.

Screens that took about a second now open instantly. A page that froze for nine seconds loads immediately. Fixed on the live system during working hours.

Sector
Retail group, dozens of branches
Year
2026
Built with
Odoo · PostgreSQL · Python

The result

Opening the transfers screen
Before
About a second 910 ms
After
Instant under 50 ms
  • The busiest screens open without a wait
  • A page that used to freeze for nine seconds now loads immediately
  • Applied to the live system during working hours — nobody stopped working
  • Users see exactly the same records, with exactly the same permissions

The situation

A retail group running dozens of branches on one ERP. Everybody knew the system was slow, and everybody had stopped mentioning it — staff had built their day around the waiting. Some screens took about a second to open. One took nine.

When a business gets to that point, the usual assumption is that the system has simply outgrown its hardware, and the fix is to spend money on a bigger server. That is an expensive assumption, and it is usually wrong.

What I found

I measured before I theorized. The slowest operations on the system pointed at two places, and neither of them was the hardware — or the ERP itself. Both were in custom code written years earlier, and both were the same mistake.

The system was asking the database for everything, pulling the whole result into memory, and only then filtering it down to the handful of rows actually on screen. On one screen that meant moving more than eighty thousand records to display eighty of them. On another, a counter that ran once per row on the page turned a single page load into a hundred and sixty separate trips to the database.

The important part: neither query looked slow on its own. They only became a problem when you counted how often they ran.

What I changed

Three things, in order of how much they mattered:

  1. Let the database do the filtering. Instead of fetching everything and narrowing it down afterwards, the code now asks a precise question and gets a precise answer. The screen’s own row limit finally reaches the database.
  2. Ask once, not once per row. The per-row counter became a single grouped query for the whole page.
  3. Added the missing indexes so the database can find matching rows directly instead of reading whole tables.

The same mistake existed in six other places. I fixed all of them, not just the two that had been reported.

The result

The transfers screen went from about a second to under fifty milliseconds. The page that froze for nine seconds now loads immediately. Memory pressure on the server dropped, because it was no longer holding tens of thousands of records per user per page load.

Nothing a user can see changed. Same records, same permissions, before and after — a performance fix that quietly changes what someone is allowed to see is not an optimization, it is a security incident.

The indexes were applied to the live production database during working hours without locking a single table, so the business never stopped trading.


For the technically minded

The two root causes were a computed search field resolving IDs in Python instead of returning a domain — which prevented the list view’s LIMIT from being pushed down — and a classic N+1 in a stored counter with no @api.depends, costing 160 sequential scans per page render. Fixes: return domains from search methods, replace the per-row counter with a single read_group, and add thirteen indexes via CREATE INDEX CONCURRENTLY so they could be built on the live database without locking. Index names were chosen to match what the ORM generates, so later module upgrades recognize them as present rather than rebuilding them.

Client names and identifying details are withheld deliberately. Every figure on this page comes from a system I can open.

No cost, no pitch

Book a free 30-minute call

Bring the problem you keep postponing. We will work out whether it is worth fixing, what it would take, and whether I am the right person for it.

  • A slow system, and nobody can say why
  • An upgrade that has stalled
  • A build about to start, and you want a second opinion
Pick a time Straight to my calendar. No form to fill in first.
Mina Adel at his desk