Hi there! I'm Maneshwar. Right now, I’m building LiveAPI, a first of its kind tool for helping you automatically index API endpoints across all your repositories. LiveAPI helps you discover, understand, and use APIs in large tech infrastructures with ease.
You’ve scaled your services, optimized your APIs, and everything’s running on the cloud… yet your app feels sluggish under load.
Chances are, your database is waving a little red flag: it's too busy.
A busy database isn't just "lots of reads and writes." It’s a deeper issue — where the database is doing too much: processing, transforming, formatting, and more.
This blog breaks down what makes a database busy, how it happens, and what you can do about it.
What's a Busy Database?
In system design, a busy database refers to a database under high stress due to:
- 🔁 High volume of queries or transactions
- 🧮 Excessive in-database processing
- ❌ Unoptimized queries or schema design
- ⛓️ Deadlocks and contention from concurrent writes
A busy DB isn’t always caused by scale — often it’s architectural choices that shift too much work to the DB layer.
Busy Database = Antipattern
This scenario has a name: the Busy Database Antipattern.
The Core Problem
Your database is no longer just storing data — it’s running logic, formatting responses, and doing things your application layer should handle.
Examples:
- Complex stored procedures and triggers
- SQL formatting of date/time/currency
- String manipulation in queries
- Generating XML/JSON blobs directly from the DB
Why is this bad?
- 🐢 DB spends more time processing, not fetching
- 🔥 Shared DB becomes a bottleneck during traffic spikes
- 💸 Cloud DBs charge for compute time (e.g., Azure DTUs)
- 🚫 DBs don’t scale out easily like compute resources
Why This Happens
Developers unintentionally fall into this trap because:
- They want queries that directly return frontend-ready data
- They try to avoid "Extraneous Fetching" (over-fetching data)
- Business logic is easier to update in stored procedures
- They treat DBs like services, not just storage
How to Fix It
Here’s the fix: Move processing to the app layer.
What Should Stay in the DB?
✅ Joins
✅ Aggregates (e.g., SUM()
, AVG()
)
✅ Filtering (WHERE
, IN
, etc.)
✅ Simple data transforms (CAST
, ROUND
)
What Should Move to App Layer?
❌ Business logic
❌ String or date formatting
❌ Complex branching logic
❌ Locale-based transformations
❌ Report generation logic
This shift lets your database do what it's best at: fast and reliable data access.
How to Detect a Busy DB
Watch for these signs:
- 📉 Throughput drops but data traffic remains low
- 🕐 DB has high CPU usage but few IOPS (reads/writes)
- ⏱️ Slow response times, especially under load
- 🐘 Queries with long execution time despite simple data needs
Steps to Investigate
Profile your database
Use tools likepg_stat_activity
,SHOW PROCESSLIST
, or your cloud provider’s insights.Monitor SQL traffic
Capture and inspect slow or CPU-heavy queries.Run controlled load tests
Vary user loads and analyze which operations choke the DB.Audit your queries
Look for formatting, branching logic, and app-layer work being done in SQL.
Key Takeaways
- A busy DB is often a design issue, not a scaling one.
- Keep your DB focused on storage and retrieval, not computation.
- Move business logic and formatting to the application layer.
- Monitor, profile, and fix early before you hit scale problems.
TL;DR
❌ Don’t | ✅ Do |
---|---|
Format currency in SQL | Format in backend |
Use stored procs for logic | Use app services |
Handle all computation in DB | Push to scalable compute layer |
Treat DB as a service | Treat DB as a repository |
Your database is not your compute engine.
Let it breathe.
Offload.
Scale smart.
LiveAPI helps you get all your backend APIs documented in a few minutes
With LiveAPI, you can quickly generate interactive API documentation that allows users to search and execute APIs directly from the browser.
If you’re tired of manually creating docs for your APIs, this tool might just make your life easier.
Top comments (1)
There is nothing wrong in transformations on the database rather than the application level. In fact, that's why views exist in the first place. However, any application should be designed to process uniform data.
More often than not, a database comes with default settings befitted to the locale of the operating system, adding another disturbance of flow or point of reconfiguration to the stack. What all SQL databases actually need as a default setting are those settings required for a main streamline of data.
So what's actually required on behalf of application development is a setting which works for the main streamline of data. Data which gets transfigured on behalf of the user and their locale at the client base only. That means, inside the database, any database, UTF-8 strings, ISO 8601 Date and Time, UTC-0 timezone. If all developers depending on the database know that this is the universal setting of the database, they are able to develop and eventually transfigure data from the database in their own client, and according to the user's needs, wherever in the world they are.
Anything else, anything other than that, may it to present different model configurations to applications through the means of a view or any other kind of transfiguration to present a model or record to the application (and I'm only talking key-value records here) - that's exactly what the database and its query engine is for.
Because, what's not mentioned in this article as to be the other side of the coin, is that when you forgo certain data processing like laid out above in my comment, you end up querying the database either multiple times or lay on it heavily due to relations (JOINs) - both blocking the database for other requests or increasing the load on the DB when it's not needed. It's always cheaper to query the database once and get the fitting response you need, through a view for example. The load of calculation and data processing is then distributed fairly between database and application. Same goes for writing into the database: use queues or use a client on a messenger bus to receive and process records to write to the database, but have the database receive records and transfigure them to the database scheme.
Also consider historization. Records not changing for a long time probably don't need the active management and treatment of a SQL database engine anymore and could be persisted better in a document-based database, which, when it comes to it, can be called on in a second-row manner when the call on the SQL database results to be unsatisfying on the request. That of course would unlink the records from the current database scheme, which is an advantage on updating the scheme, but sets the persisted records in requirement for transfiguration or, as I'd advise it, a transfiguring application layer designed to treat historic records for present needs.
So there are many ways to go about it, and many ways which don't need to be a blunt solution for either side of the problem.