Why Your MySQL COUNT(*) Is Slow and How to Fix It (Beginner Friendly Guide)
Why Your MySQL COUNT(*) Query Is Slow — And How to Fix It (Beginner-Friendly Tutorial)
Welcome back to another “problem & solution” style database tutorial!
Today’s issue is super common:
"My COUNT(*) query is slow. Why??"
Don’t worry. You’re not dumb. Many developers—especially beginners—don’t know how MySQL actually processes counting.
Let’s break it down step by step, in a fun, friendly, newbie-friendly way.
1. What COUNT(*) Actually Does (And Why It Hurts)
When you run:
You might think MySQL just reads some saved number.
But no.
MySQL will often scan the entire table, row by row, to count them.
If your table has:
-
500,000 rows → OK
-
20 million rows → painful
-
100+ million rows → catastrophic
Why does this happen?
Because MySQL storage engines store data differently:
MyISAM
-
Keeps row count metadata
-
COUNT(*)is instant
InnoDB
-
Does not store row counts
-
Must read all rows
Most modern servers use InnoDB, so your COUNT(*) is naturally slow.
2. The Real Reasons Your COUNT(*) Is Slow
Here are the common causes:
✅ Reason #1: No index on filtered COUNT
Example:
If status is not indexed, MySQL scans every row.
✅ Reason #2: Table is huge
✅ Reason #3: Using SELECT COUNT(column) instead of COUNT(*)
Some engines optimize COUNT(*) better than COUNT(id).
✅ Reason #4: Locked tables or high traffic
Your count query waits behind others.
3. How to Fix Slow COUNT(*) Queries (Step-by-Step)
Here comes the important part: making it fast.
Step 1: Add an Index (The #1 Fix)
If you run:
Then create an index:
Why this works:
MySQL can count matching rows inside the index
→ no need to scan full table
→ massive speed boost
Step 2: Avoid COUNT(column) — Use COUNT(*)
Bad (slower on some engines):
Better:
Why?
-
MySQL can optimize
COUNT(*)better -
It doesn’t load actual data, just metadata pointers
Step 3: Use a Summary Table (Best for Big Data)
If you count rows very often, don’t count them live.
Create a small table that stores updated counts.
Example summary table:
Update using trigger or cron job.
Now counting becomes:
⚡ Lightning fast — microseconds
Step 4: Cache the Result
If the count doesn’t need to be real-time, cache it using:
-
Redis
-
Memcached
-
Application-level caching
-
WordPress transient API (if using WP)
Example Redis approach:
If empty → run SQL → set cache
Step 5: Use EXPLAIN to See Why It's Slow
Run:
If you see:
It means full table scan → add index
If you see:
It’s using the index → good
4. Advanced Methods (For Large Enterprise Tables)
For extremely large databases (100M+ rows):
Option A — Partitioning
Split table into smaller pieces
MySQL counts faster
Option B — Use Approximate Counting
HyperLogLog, ClickHouse, BigQuery
Useful when exact count isn’t needed
Option C — Use MySQL Engine Stats
This gives approximate row count
(Useful for dashboards)
5. Example: Before and After Optimization
Original slow query:
Execution time: 8.2 seconds
After adding index:
Execution time: 0.02 seconds
🔥 400x faster
🔥 no code change
🔥 beginner friendly fix
6. Final Tips for Newbies
Here’s your quick takeaway list:
✔ Add indexes for filtered counts
✔ Use COUNT(*) instead of COUNT(id)
✔ Cache repeated counts
✔ Use summary tables for dashboards
✔ Use EXPLAIN to verify performance
✔ Don’t panic — everyone has slow COUNT queries at first
If you follow the steps above, your MySQL counting will go from “slow and annoying” to “instant and smooth”.