Skip to content
  1. Home
  2. Blog
Performance

The slow page was never the server: notes from 14 performance rescues

Ahmed Raza

Ahmed Raza

· 3 min read

The slow page was never the server: notes from 14 performance rescues

Founders call me when the app "needs a bigger server". In fourteen rescues, a bigger server fixed exactly one of them.

The pattern is always the same. A Laravel app that felt fast at 200 customers now takes four seconds to load a dashboard at 3,000. Someone has already doubled the database instance, the bill went up and the page did not get faster. Then they find me.

Measure before you touch anything

I start every rescue by turning on query logging for one real user session and counting. The worst I have seen was a customer list that ran 1,412 queries for 50 rows. The median across the fourteen projects was 230 queries on the slowest page. No server upgrade survives numbers like that.

Laravel Debugbar is fine locally, but production data is what matters. I use a small middleware that logs query count and total query time per request to a separate table for one week. Sorting that table by total time spent across all users tells you which three pages to fix first, and it is rarely the page the founder complained about.

The four fixes that do most of the work

Eager loading the relationships the view actually uses. A missing composite index on the two columns every tenant query filters by, usually tenant_id and created_at. Moving PDF generation, emails and webhooks to a queue. And caching the three numbers on the dashboard that are recalculated on every page view but only change once an hour.

On a Manchester property management app those four changes took the dashboard from 3.8 seconds to 410 milliseconds, and the database instance went back down two sizes. That saved them $640 a month, which paid for my two weeks in under five months.

When the server really is the problem

The one exception was a reporting tool running on a single small VPS with MySQL, Redis, queue workers and the web server all fighting for 2 GB of RAM. Splitting the database onto its own machine was the right call there. But we knew that only because we had measured first.

Comments

Comments


Comment created and will be displayed once approved.