Feb 13, 2024 · 2 min read · Backend Engineering and Architecture
Fixing a Slow PostgreSQL Dashboard
A B2B dashboard took several seconds to load and the database looked like the problem. The real issue wasn’t its capacity, but the way the application was asking for the data.
While working on a B2B operations platform, I built a dashboard that got slower as the amount of business data increased. Nothing was completely broken. The dashboard was just slow enough to be irritating every time someone opened it, which happened throughout the day. The database was clearly involved, so increasing its resources looked like a reasonable solution. More CPU or memory probably would have improved the response temporarily. But it wouldn’t have fixed what the application was doing.
The Dashboard Queries
The dashboard combined totals, status summaries, recent activity, and data grouped across different parts of the operation. From the user’s perspective, it was one page. From the database’s perspective, it was a sequence of queries with joins, filters, and aggregations over data that had grown significantly since the first version. Some filters didn’t align with the available indexes. One aggregation recalculated information that didn’t need to be rebuilt for every request. The API also fetched details that the dashboard never displayed. No single query looked disastrous when tested with a small dataset. Under production-like data and repeated use, the combined cost was obvious. So saying “the database is slow” wasn’t enough. We needed to understand the work the application was giving it.
The Real Access Pattern
I started by looking at the queries generated by the critical requests and how the database executed them. We weren’t trying to make every query perfect, only to find the few operations responsible for most of the waiting time. We changed the queries that mattered, added indexes based on the real filters, removed data the dashboard didn’t use and stopped recalculating stable information on every page load. The response dropped from several seconds to under one second in the workflows we worked on. The client didn’t care which index we added or what changed in the query plan. They cared that a dashboard they opened throughout the day was fast again. We never needed to replace the database. The application just needed to ask less from it on every page load.