文章目录
- 前言
-
- 一、如何锻炼这种优化思维?
- 二、需要了解业务吗?
- [三、用什么工具测试慢 SQL?](#三、用什么工具测试慢 SQL?)
-
- [工具 1:MySQL 自带 --- EXPLAIN(最常用)](#工具 1:MySQL 自带 — EXPLAIN(最常用))
- [工具 2:查看实际执行时间](#工具 2:查看实际执行时间)
- [工具 3:DBeaver 自带的功能](#工具 3:DBeaver 自带的功能)
- [工具 4:慢查询日志(生产环境)](#工具 4:慢查询日志(生产环境))
- [四、实战:从 0 到优化的完整步骤](#四、实战:从 0 到优化的完整步骤)
- 五、一句话速成心法
前言
三个层面:思维方法 、业务理解 、工具使用。
一、如何锻炼这种优化思维?
核心原则就一句话
能不查的就不查,能少查的就少查,能提前过滤就提前过滤。
对应回这个优化:
js
优化前: 查所有流程 → 行转列 → 再过滤(先查10万行,再扔掉9.9万行)
优化后: 先圈出我的流程 → 只查这100个流程的变量(只查100行)
三个"灵魂拷问"
每次写/改 SQL 时问自己:
| 拷问 | 对应优化 | 原 SQL 的问题 |
|---|---|---|
| ① 我需要查哪些行? | 用 WHERE 先过滤 | 没有先过滤,全部查完再说 |
| ② 同样的数据查了几遍? | 用 CTE 只查 1 次 | 行转列重复了 8 遍 |
| ③ 能不能先缩小范围再做复杂计算? | 先查 ID 再查详情 | 直接对全表做行转列 |
一个具体的锻炼方法
拿到慢 SQL,先画出数据流向图:
js
输入:act_hi_varinst(10万行)
│
├─ 子查询1 → 行转列 → 10万行
├─ 子查询2 → 行转列 → 10万行 ← 重复!
├─ 子查询3 → 行转列 → 10万行 ← 重复!
│
└─ 最后过滤:WHERE BELONG='srm'
→ 还剩 1万行(90% 白查了!)
看到这个图,问题一目了然:
- 重复 → 用 CTE
- 查太多 → 先圈定范围
二、需要了解业务吗?
需要,但不需要很深。
这个优化中需要知道的业务知识
| 知识点 | 为什么需要 | 不知道会怎样 |
|---|---|---|
| 每个用户只看到自己的流程 | 才能用 WHERE assignee=当前用户 缩小范围 |
不敢加这个条件 |
| BELONG='srm' 只筛选出 SRM 模块 | 提前过滤不相关数据 | 过滤时机放错了 |
| 审批人有8种状态 | 才知道 UNION ALL 有8个分支,各是什么含义 | 不敢合并/不敢改 |
不需要知道的
| 知识点 | 不需要知道 |
|---|---|
| 审批流程的具体业务规则 | 不影响 SQL 优化 |
| 每种审批状态的业务含义 | 只要知道查询条件就行 |
| 前端怎么展示这些数据 | 不影响 SQL 优化 |
结论
您只需要知道"这个 SQL 是用来查什么的,查的是谁的数据",这个程度就够了。
比如这个 SQL,您只需要知道:
- 查的是"当前登录用户"的待办/已办列表
- 每个用户只能看到自己的
知道这两点,就足够推理出:应该先按用户 ID 过滤,再查其他数据。
三、用什么工具测试慢 SQL?
工具 1:MySQL 自带 --- EXPLAIN(最常用)
sql
-- 在 SQL 前面加 EXPLAIN
EXPLAIN SELECT ... FROM ...
输出解读:
| 列 | 含义 | 好 | 坏 |
|---|---|---|---|
type |
访问方式 | const, ref, range |
ALL(全表扫描) |
rows |
预估扫描行数 | 几百 | 几万+ |
Extra |
额外信息 | Using index |
Using temporary, Using filesort |
您的项目实战:
sql
-- 优化前看 rows
EXPLAIN SELECT ... FROM act_hi_varinst ...
-- rows: 100000 ← 全表扫描
-- type: ALL ← 没有索引
-- 优化后看 rows
EXPLAIN WITH user_proc_inst AS (...) ...
-- rows: 100 ← 只查100行
-- type: range ← 走索引
工具 2:查看实际执行时间
sql
-- MySQL 开启执行时间
SET profiling = 1;
-- 执行你的 SQL
SELECT ...;
-- 查看执行时间
SHOW profiles;
-- 输出:Duration: 3.2 sec ← 3.2秒,慢!
工具 3:DBeaver 自带的功能
DBeaver 中选中 SQL → 右键 → 选 "Explain Plan"(执行计划):
js
Operation | Object | Cost | Rows |
-----------------------------|-------------------|-------|-------|
TABLE SCAN (FULL) | act_hi_varinst | 10000 | 100000|
GROUP BY | | | |
NESTED LOOP JOIN | | | |
直接看出全表扫描 和预估行数。
工具 4:慢查询日志(生产环境)
sql
-- 查看慢查询是否开启
SHOW VARIABLES LIKE 'slow_query%';
-- 设置慢查询阈值(超过1秒的记录)
SET long_query_time = 1;
-- 查看慢查询日志文件路径
SHOW VARIABLES LIKE 'slow_query_log_file';
四、实战:从 0 到优化的完整步骤
假设您现在接手一个慢 SQL:
js
第1步:找到慢 SQL
└─ DBeaver 执行时转圈圈 → 卡了几秒
└─ 或从慢查询日志捞出来
第2步:EXPLAIN 分析
└─ 看到 type = ALL(全表扫描)
└─ 看到 rows = 100000
└─ 看到 Extra = Using temporary(用了临时表)
第3步:画数据流向图
└─ 输入10万行 → 子查询重复8次 → 最后才过滤
第4步:问三个问题
① 需要查哪些行? → 只查当前用户的
② 查了几遍? → 8遍
③ 能先缩小吗? → 能!先查用户ID
第5步:改写
└─ 用 CTE + 先圈范围
第6步:对比验证
└─ EXPLAIN 看 rows 从 10万 → 100
└─ 实际执行从 3秒 → 200毫秒
五、一句话速成心法
遇到慢 SQL,先问"能不能提前干掉不需要的数据",再问"同样的东西查了几遍"。
就像打扫房间:
- 先扔掉垃圾(不需要的过滤掉)
- 再收拾剩下的(对需要的数据做计算)
- 而不是先全部摆出来再分类(全表扫描后再过滤)
这个项目里的优化,本质上就是把"先全部查出来再说"改成了"先确定要查什么,再去查"。