sql优化思维

文章目录


前言

三个层面:思维方法业务理解工具使用


一、如何锻炼这种优化思维?

核心原则就一句话

能不查的就不查,能少查的就少查,能提前过滤就提前过滤。

对应回这个优化:

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% 白查了!)

看到这个图,问题一目了然:

  1. 重复 → 用 CTE
  2. 查太多 → 先圈定范围

二、需要了解业务吗?

需要,但不需要很深。

这个优化中需要知道的业务知识

知识点 为什么需要 不知道会怎样
每个用户只看到自己的流程 才能用 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,先问"能不能提前干掉不需要的数据",再问"同样的东西查了几遍"。

就像打扫房间:

  • 先扔掉垃圾(不需要的过滤掉)
  • 再收拾剩下的(对需要的数据做计算)
  • 而不是先全部摆出来再分类(全表扫描后再过滤)

这个项目里的优化,本质上就是把"先全部查出来再说"改成了"先确定要查什么,再去查"

相关推荐
oradh1 小时前
Oracle物理存储结构概述
数据库·oracle·物理结构·oracle基础·oracle入门·oracle物理存储结构概述
m0_463672201 小时前
Golang如何用火焰图分析性能_Golang火焰图教程【对比】
jvm·数据库·python
m0_591364731 小时前
Go语言怎么做链路追踪_Go语言分布式链路追踪教程【精选】
jvm·数据库·python
l1t1 小时前
DeepSeek总结的欢迎来到 ORDER BY 丛林
数据库·算法
m0_463672201 小时前
HTML函数工具是否支持雷蛇等游戏外设_RGB同步汇总【汇总】
jvm·数据库·python
黄昏晓x2 小时前
数据库----索引
数据库
志栋智能2 小时前
安全、稳定是超自动化运维的底座
网络·数据库·人工智能
iAm_Ike2 小时前
如何用 IndexedDB 存储从 API 获取的超大列表并实现二级索引
jvm·数据库·python
数据最前线2 小时前
亡羊补牢?Oracle 计划推出月度安全补丁
数据库·oracle