——让数据库从“喘气”到“起飞”
1. 引子:你以为数据库慢是天生的?
实际项目中,经常听到这样的抱怨:
- “为什么查个列表要8秒?”
- “这点数据,怎么这么慢?”
- “是不是服务器配小了?”
很多人第一反应是:换服务器、加内存、买更贵的云服务。
但是,专业工程师知道:
99%的数据库性能问题,根本原因是SQL本身写得不对。
今天,带你看一次真实的SQL优化实战,从慢到快,全过程拆解。
2. 问题背景
- 业务:订单系统后台,分页查询订单列表
- 症状:查询耗时 8秒,页面直接白屏超时
- 数据量:订单表 2000万条记录
- 数据库:MySQL 8.0
3. 原始SQL(慢得让人怀疑人生)
SELECT * FROM orders
WHERE status = 'completed'
ORDER BY created_at DESC
LIMIT 1000, 20;
问题分析:
- ORDER BY + OFFSET 分页,导致数据库必须扫到1000条数据再取出20条
created_at字段没有索引,只能全表扫描- **select *** ,查了很多其实页面用不到的字段
👉 小总结:
分页深了+无索引+查太多字段=三重地狱模式。
SQL查询性能优化流程
原始慢查询
↓
加索引(Indexing)
↓
改分页(Cursor-based Pagination)
↓
只查必要字段(Select needed fields)
↓
覆盖索引(Covering Index)
↓
飞一般的查询速度
4. 第一步优化:加索引
直接在created_at字段上加索引:
ALTER TABLE orders ADD INDEX idx_created_at (created_at);
重新执行,查询时间:3.2秒。
👉 小改善,但还是慢,原因是OFFSET问题没解决。
5. 第二步优化:改写分页逻辑("深分页"必杀技)
传统分页 LIMIT 1000, 20 的问题是:数据库必须跳过前1000条才能拿到后面的20条,很累。
更好的做法是基于上次的最大created_at时间继续查:
SELECT * FROM orders
WHERE status = 'completed'
AND created_at < '上次最后一条的created_at'
ORDER BY created_at DESC
LIMIT 20;
(第一次查普通分页,后续根据created_at翻页)
执行时间: 380毫秒!
深分页 vs 基于游标分页对比
分页方式 | 查询特点 | 查询速度 |
| :-------------------- | :---------------- | :--- |
| 深分页(OFFSET分页) | 跳过前N条再取后面数据,数据库累死 | 越深越慢 |
| 游标分页(基于created_at或ID) | 直接定位起点,拿需要的数据 | 极速返回
6. 第三步优化(进一步压榨性能)
- 只select必要字段(不要
select *) - 覆盖索引:只查询索引里能cover到的字段,直接用索引返回,避免回表
覆盖索引示意
普通索引查询:
搜索索引 → 拿到主键 → 回表查询实际数据(慢)
覆盖索引查询:
搜索索引 → 直接返回需要字段(快)
比如:
SELECT order_id, user_id, amount, created_at
FROM orders
WHERE status = 'completed'
AND created_at < '上次最后一条的created_at'
ORDER BY created_at DESC
LIMIT 20;
如果再把order_id, user_id, amount, created_at都加进联合索引里:
ALTER TABLE orders
ADD INDEX idx_status_createdat (status, created_at, order_id, user_id, amount);
查询时间: 300毫秒以内!
7. 优化前后对比图
原始查询:8秒
↓
加索引后:3.2秒
↓
改分页后:380毫秒
↓
覆盖索引后:300毫秒以内
性能提升了整整26倍!
执行时间(ms)
│
│ ┌───────────────
│ ┌─┘
│ ┌─┘
│ ┌─┘
│ ┌─┘
│─┘────────────────────> 优化次数
原始8秒 → 3.2秒 → 380毫秒 → 300毫秒以内
8. 小结
一次好的SQL优化,通常遵循这四步:
| 步骤 | 关键操作 |
|---|---|
| 1 | 加索引,走最优执行计划 |
| 2 | 改分页方式,避免OFFSET深分页 |
| 3 | 精简字段,只查必要数据 |
| 4 | 用覆盖索引,减少回表开销 |
而不是盲目地"换服务器"、"加内存"。
优化代码,比烧钱扩容更有效、更有成就感!
9. 彩蛋:一句话记住SQL优化核心
给你一句最硬核的总结:
能走索引,就不全表扫描;能覆盖索引,就不回表;能浅分页,就不深分页。
背下来,面试、实战、打怪升级通通够用!