6、一次SQL优化实战:从8秒到300毫秒的真实案例

252 阅读3分钟

——让数据库从“喘气”到“起飞”


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优化核心

给你一句最硬核的总结:

能走索引,就不全表扫描;能覆盖索引,就不回表;能浅分页,就不深分页。

背下来,面试、实战、打怪升级通通够用!