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