18/08/2025
π TOP 4 SQL QUERY "CULPRITS" MAKING YOUR BACKEND SLOW AS MOLASSES & SOLUTIONS! β
"Why is this so damn slow? It's just a simple 'SELECT *' query!" - Over 60 seconds have passed, the loading icon on your screen keeps spinning, but you still don't know what to do next...
The pressure weighs heavier on your shoulders when the deadline is just 1 hour away and you need to demo for the client. Your phone keeps buzzing with messages from your boss: "Hey, how's it going?", "The client is waiting!"
"Same piece of code was running fine last week, why is it running so slow today?" - You start to panic π¨
This is a story that happens all too often when you're working on real projects. And the main culprit is those SQL queries you write every day without even knowing it.
--------------
π TOP 4 COMMON SQL QUERY "CULPRITS"
---1. "SELECT *" Query - The Ticking Time Bomb---
β Don't do this: SELECT * FROM users WHERE status = 'active';
β
Do this instead: SELECT id, name, email FROM users WHERE status = 'active';
Why it slows things down:
- Increased network bandwidth: Database has to transfer all data from every column, including unnecessary ones. With 1000 users, instead of transferring 50KB of needed data, the server might have to transfer up to 100MB of redundant data.
- RAM consumption: Server has to load all data into memory before sending it to the client. For example, if a table has 20 columns but you only need 3 columns β you're wasting 85% of RAM.
- Slow disk I/O: Database has to read from many different pages on the disk instead of just reading from a few pages containing the needed columns.
- Inefficient caching: Database cache becomes less effective because it has to store all the redundant data.
When you CAN use SELECT * :
- Small tables (under 1000 records) with few columns (under 10 columns).
- Development/Debug: when you need to see all data for inspection.
---2. Queries Without INDEX---
β Full table scan query: SELECT id, customer_id, total FROM orders WHERE customer_id = 12345;
β
Solution: CREATE INDEX idx_customer_id ON orders(customer_id);
Why it slows things down: Database has to read every single row in the entire table to find customer_id = 12345. It's like flipping through every page of a book from start to finish until you find the result.
However, you don't always need to create indexes. Here are some common cases where you shouldn't create indexes:
- Small tables (under 5000 rows): Full table scan can actually be faster than using an index.
- Columns with few values (like gender: only Male/Female): Index is ineffective.
- Tables with frequent INSERT/UPDATE operations: Will slow down INSERT/UPDATE processes.
- Columns never used in WHERE/JOIN: Index just wastes disk space.
---3. Queries with LIKE '%...%'---
β Don't do this: SELECT * FROM products WHERE name LIKE '%iphone%';
β
Better options:
- SELECT * FROM products WHERE name LIKE 'iphone%';
- Use Full-Text Search.
Why it slows things down:
- Index becomes useless: When you have % at the beginning (%iphone%), database can't use the index on the name column. Index only works when it knows exactly what character to start with.
- Slow string comparison: Database has to perform pattern matching for every row. With 100,000 products, the server has to check if the substring "iphone" exists in each product name.
- Can't be cached: Results from LIKE '%...%' are very hard to cache effectively because there are countless variations.
When you CAN use LIKE '%...%':
- Small tables (under 5000 rows): Performance impact is negligible.
- One-time data cleanup: Scripts running offline, don't affect user experience.
- Can combine with LIMIT: LIKE '%keyword%' LIMIT 10.
---4. Nested Queries (N+1 Problem)---
Common when working with ORM in frameworks:
β Don't do this:
const users = await User.findAll();
for (const user of users) {
user.postCount = await Post.count({ where: { userId: user.id }});
} // 1 + N queries!
β
Solution:
const users = await User.findAll({ include: Post }); // 1 query
Why it slows things down:
- Too many queries: With 100 users, instead of 1 database query, you're creating 101 queries (1 + 100). Each query (connection) has a certain network latency (usually 1-5ms).
- Connection pool exhaustion: Database has a limit on concurrent connections. N+1 queries can exhaust the pool, making other requests wait.
- Database lock conflicts: Many small queries create more opportunities for lock conflicts, especially when there are other write operations.
When N+1 might be acceptable:
- Lazy loading with cache: If relationships are already cached in Redis/Memcached.
- Small loops (under 10 items).
- Development/prototype: Temporary for quick coding, optimize later.
--------------
π 5 BASIC STEPS TO CHECK AND OPTIMIZE QUERIES YOU MUST KNOW
Step 1: Use EXPLAIN
EXPLAIN SELECT * FROM users WHERE email = '[email protected]';
Step 2: Check ex*****on time Any query taking over 100ms should be reviewed.
Step 3: Create indexes for frequently searched columns
CREATE INDEX idx_email ON users(email);
CREATE INDEX idx_status_created ON users(status, created_at);
Step 4: Use pagination instead of fetching all data when dealing with large datasets
SELECT id, name FROM users LIMIT 20 OFFSET 0;
Step 5: Use cache for complex queries (Redis)
--------------
π€ HOW DO YOU KNOW YOU'VE OPTIMIZED WELL ENOUGH?
- Response time under 200ms for basic queries.
- Database server CPU usage stays stable under 70%.
- No queries in the slow query log.
- Users feel the application is "smooth" and "fast".
--------------
β
REMEMBER!
π Query optimization isn't just a skill, it's an art of balancing performance and complexity. This is when you transition from "copying code" to "understanding the essence" - and your skill level truly skyrockets.