同步 · dev.to / @markyu
A practical MySQL workflow for finding slow queries, reading EXPLAIN output, and deciding whether an index actually helps.
- 发布日期
- May 20 '24
- 阅读时长
- 3 min read
- 点赞
- 13
- 评论数
- 2
The fastest way to make MySQL worse is to add indexes because a query "feels slow."
Start with evidence. Find the query. Measure it. Read the plan. Then change one thing.
Here is the workflow I use.
1. Confirm MySQL Is Actually the Bottleneck
Do not start inside EXPLAIN. First check if the database is under obvious stress.
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Innodb_rows_read';
SHOW GLOBAL STATUS LIKE 'Com_select';These numbers do not solve the problem, but they tell you where to look.
If Slow_queries is climbing during the incident, turn to the slow query log. If connections are spiking, you may have an app pooling problem. If rows read is exploding, you probably have missing selectivity or a bad access pattern.
2. Turn On the Slow Query Log
Check the current setting:
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
SHOW VARIABLES LIKE 'slow_query_log_file';Enable it for the running server:
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;For persistent config, add this to your MySQL config:
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 0I usually avoid turning on log_queries_not_using_indexes at first. It can create noise. A query can skip indexes and still be fine on a small table. Start with actual slow queries.
3. Summarize the Worst Queries
Use mysqldumpslow when you need a quick local read:
mysqldumpslow -s t -t 10 /var/lib/mysql/*-slow.logUseful sort modes:
mysqldumpslow -s t -t 10 /var/lib/mysql/*-slow.log # total query time
mysqldumpslow -s at -t 10 /var/lib/mysql/*-slow.log # average query time
mysqldumpslow -s c -t 10 /var/lib/mysql/*-slow.log # countI care about two classes:
- A query that runs rarely but takes forever.
- A query that is individually mediocre but runs thousands of times.
Both can hurt production.
4. Run EXPLAIN on the Real Query
Say the slow log points to this:
SELECT id, title, published_at
FROM posts
WHERE author_id = 42
AND status = 'published'
ORDER BY published_at DESC
LIMIT 20;Run:
EXPLAIN
SELECT id, title, published_at
FROM posts
WHERE author_id = 42
AND status = 'published'
ORDER BY published_at DESC
LIMIT 20;The columns I check first:
| Column | What I look for |
|---|---|
type | ALL means full scan. Not always bad, but suspicious on large tables. |
possible_keys | Indexes MySQL could use. |
key | The index MySQL actually used. |
rows | Estimated rows scanned. |
Extra | Watch for Using filesort and Using temporary. |
5. Add the Index That Matches the Query
For the query above, this is a practical index:
CREATE INDEX idx_posts_author_status_published
ON posts (author_id, status, published_at DESC);Why this order?
author_idis an equality filter.statusis another equality filter.published_atsupports the sort after filtering.
Then run EXPLAIN again. If rows drops and the sort gets cheaper, you probably helped.
6. Do Not Keep Every Index
Indexes speed reads but slow writes and consume memory/disk. Every new index should pay rent.
Check existing indexes:
SHOW INDEX FROM posts;If two indexes overlap, you may not need both.
Example:
INDEX (author_id)
INDEX (author_id, status, published_at)The longer composite index can often satisfy lookups that start with author_id. Do not delete blindly, but do question duplicates.
7. The Mistakes I See Most
Adding an index on the wrong single column:
CREATE INDEX idx_posts_status ON posts (status);If almost every row is published, this index is low value.
Using functions on indexed columns:
WHERE DATE(published_at) = '2026-06-16'Prefer a range:
WHERE published_at >= '2026-06-16'
AND published_at < '2026-06-17'Selecting more columns than needed:
SELECT * FROM posts ...Make the query say what the screen actually needs.
My Checklist
- Find the slow query from logs, not vibes.
- Reproduce the query with realistic parameters.
- Run
EXPLAIN. - Add one index that matches filters and sorting.
- Run
EXPLAINagain. - Measure the endpoint again.
- Remove indexes that do not earn their cost.
Performance work is not magic. It is a loop: observe, change, measure.
相关阅读
Bad Data Quality Costs More Than a Slow Query
A practical data quality guide for engineers: validation, ownership, schema drift, observability, and fixing bad data before dashboards lie.
data
Java BeanUtils Copying: Convenient, but Not Free
A practical Java guide to BeanUtils, shallow copy pitfalls, reflection overhead, and when MapStruct or manual mapping is a better choice.
java
RedisJSON Is Useful When You Update Parts of a Document
A practical RedisJSON walkthrough: when to use it, when not to, and the commands that actually matter.
redis
原文发布
本文首发于 dev.to,评论与点赞保留在原站。
在 dev.to 继续阅读