当前位置: 首页 > news >正文

EXPLAIN-从入门到精通-数据库优化必备神器

EXPLAIN:从入门到精通,数据库优化必备神器

你有没有遇到过这种情况——一条 SQL 在本地跑得飞快,一上线就卡成 PPT?
今天咱们就来聊聊数据库优化的"照妖镜":EXPLAIN。


一、问题引入:那条让我加班到凌晨的 SQL

上周有个线上告警,一个查询接口响应时间从 50ms 暴涨到 15 秒。

我第一反应是:是不是数据量暴增了?查了一下,也就从 10 万涨到了 12 万,不至于啊。

第二反应:是不是锁竞争?看了监控,也没啥锁等待。

最后祭出大招——EXPLAIN一看,好家伙,全表扫描!原来新来的实习生把索引字段的类型改了,导致索引失效。

说白了,EXPLAIN 就是数据库的"CT 机",能让你一眼看穿 SQL 的执行真相。


二、EXPLAIN 到底是什么?

2.1 一句话定义

EXPLAIN 是数据库提供的执行计划分析工具,它会告诉你:数据库打算怎么执行你的 SQL,是走索引还是全表扫描,先查哪张表,怎么 join,预估要扫描多少行…

2.2 为什么要用它?

咱们写 SQL 的时候,心里想的是"我要什么数据",但数据库想的是"我怎么高效地拿到这些数据"。

这中间有个鸿沟——你以为的"高效"和数据库实际的"执行"可能差十万八千里

EXPLAIN 就是帮你填这个沟的。


三、EXPLAIN 怎么用?(以 MySQL 为例)

3.1 基础用法

-- 直接在 SQL 前面加个 EXPLAINEXPLAINSELECT*FROMusersWHEREage>18;

输出大概长这样:

idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEusersALLNULLNULLNULLNULL100000Using where

关键字段解读:

字段什么意思重点关注
type访问类型最重要!从优到劣:system > const > eq_ref > ref > range > index > ALL
key实际使用的索引NULL 表示没用索引,要警惕
rows预估扫描行数越小越好,上万就要注意了
Extra额外信息Using filesort、Using temporary 都是危险信号
possible_keys可能用到的索引看看有没有合适的索引被忽略了

3.2 进阶用法

-- 看更详细的执行计划(MySQL 5.6+)EXPLAINFORMAT=JSONSELECT*FROMusersWHEREage>18;-- 看实际执行情况(MySQL 5.6+)EXPLAINANALYZESELECT*FROMusersWHEREage>18;-- 看执行计划 + 实际执行统计(MySQL 8.0.18+)EXPLAINANALYZESELECT*FROMusersWHEREage>18;

3.3 一个实际案例

假设咱们有个订单表:

CREATETABLEorders(idBIGINTPRIMARYKEY,user_idBIGINTNOTNULL,statusVARCHAR(20)NOTNULL,created_atDATETIMENOTNULL,INDEXidx_user(user_id),INDEXidx_status(status));

来条 SQL:

EXPLAINSELECT*FROMordersWHEREuser_id=10086ANDstatus='PAID'ORDERBYcreated_atDESCLIMIT10;

不好的执行计划长这样:

type: ref key: idx_user rows: 5000 Extra: Using where; Using filesort

问题在哪?

  • 用了idx_user索引,但还要回表 5000 行
  • Using filesort:内存排序,数据量大就惨了

优化方案:建个联合索引

ALTERTABLEordersADDINDEXidx_user_status_created(user_id,status,created_at);

优化后的执行计划:

type: ref key: idx_user_status_created rows: 50 Extra: Using index -- 覆盖索引,不用回表了!

从 5000 行扫描降到 50 行,还没有 filesort,这就是 EXPLAIN 的价值。


四、主流数据库 EXPLAIN 对比

特性MySQLPostgreSQLOracleSQL Server
基本语法EXPLAIN SQLEXPLAIN SQLEXPLAIN PLAN FORSET SHOWPLAN_ALL ON
看实际执行EXPLAIN ANALYZE(8.0.18+)EXPLAIN ANALYZEDBMS_XPLAN.DISPLAYSET STATISTICS PROFILE ON
输出格式表格 / JSON文本 / JSON / XML表格 / XML表格 / XML / JSON
成本估算有(相对值)有(相对值)有(绝对值,最准)有(相对值)
索引提示USE INDEX/FORCE INDEX不支持强制索引/*+ INDEX() */WITH (INDEX())
可视化工具Workbench、NavicatpgAdminSQL DeveloperSSMS

4.1 MySQL vs PostgreSQL 详细对比

MySQL 的 EXPLAIN:

EXPLAINSELECT*FROMusersWHEREemail='test@example.com';-- 输出:-- +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+-- | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |-- +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+-- | 1 | SIMPLE | users | NULL | const | PRIMARY | PRIMARY | 8 | const | 1 | 100.00 | NULL |-- +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+

特点:

  • 表格形式,直观好读
  • type字段是核心判断依据
  • Extra里的Using filesortUsing temporary是性能杀手

PostgreSQL 的 EXPLAIN:

EXPLAINANALYZESELECT*FROMusersWHEREemail='test@example.com';-- 输出:-- Index Scan using idx_users_email on users (cost=0.29..8.30 rows=1 width=72) (actual time=0.023..0.024 rows=1 loops=1)-- Index Cond: (email = 'test@example.com'::text)-- Planning Time: 0.123 ms-- Execution Time: 0.045 ms

特点:

  • 树形结构,更贴近实际执行流程
  • cost=0.29..8.30:启动成本…总成本
  • actual time:真实执行时间(EXPLAIN ANALYZE 才有)
  • 能看到每个节点的实际耗时,定位瓶颈更精准

4.2 Oracle 的 EXPLAIN PLAN

-- 先生成执行计划EXPLAINPLANFORSELECT*FROMusersWHEREemail='test@example.com';-- 再查看SELECT*FROMTABLE(DBMS_XPLAN.DISPLAY);-- 输出:-- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-- |-----|-------------------|---------------|-------|-------|------------|----------|-- | 0 | SELECT STATEMENT | | 1 | 72 | 2 (0)| 00:00:01 |-- | 1 | INDEX UNIQUE SCAN| PK_USERS_EMAIL| 1 | 72 | 2 (0)| 00:00:01 |

特点:

  • 成本是绝对值(基于 I/O、CPU、内存的综合估算)
  • Cost (%CPU)能看出 CPU 占比
  • 企业级功能最全,但也是最复杂的

4.3 SQL Server 的 Execution Plan

-- 开启实际执行计划(SSMS 里按 Ctrl+M 也行)SETSTATISTICSPROFILEON;GOSELECT*FROMusersWHEREemail='test@example.com';GOSETSTATISTICSPROFILEOFF;

特点:

  • SSMS 的图形化执行计划是业界最好用的
  • 鼠标悬停能看到每个操作的详细开销
  • 能直接对比两个执行计划的差异

五、EXPLAIN 核心判断法则

5.1 type 字段优先级(MySQL)

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 目标:至少达到 range,最好是 ref 以上

常见 type 解读:

type含义好坏
const主键/唯一索引等值查询🟢 最佳
eq_refjoin 时主键/唯一索引匹配🟢 很好
ref普通索引等值查询🟢 不错
range索引范围查询🟡 可接受
index全索引扫描🟠 警惕
ALL全表扫描🔴 危险

5.2 Extra 里的危险信号

-- 🚨 Using filesort:内存排序,大数据量会爆炸EXPLAINSELECT*FROMusersORDERBYname;-- 没索引,得排序-- 🚨 Using temporary:用了临时表,通常发生在 GROUP BY / DISTINCTEXPLAINSELECTstatus,COUNT(*)FROMusersGROUPBYstatus;-- 🚨 Using where; Using join buffer:join 没走索引,用了缓存区EXPLAINSELECT*FROMusers uJOINorders oONu.name=o.user_name;

5.3 一个快速诊断 checklist

□ type 是不是 ALL?是 → 考虑加索引 □ key 是不是 NULL?是 → 索引没生效,检查条件 □ rows 是不是上万?是 → 扫描量太大,优化条件或索引 □ Extra 有没有 filesort?有 → 优化 ORDER BY □ Extra 有没有 temporary?有 → 优化 GROUP BY / DISTINCT

六、常见坑与误区

坑 1:EXPLAIN 的 rows 是估算,不是实际

-- MySQL 用索引统计信息估算,可能不准-- 特别是数据分布不均匀的时候ANALYZETABLEusers;-- 更新统计信息后再看

坑 2:EXPLAIN 和实际执行可能不一样

-- MySQL 5.7 之前,EXPLAIN 不走实际执行-- 有些优化(如条件下推)可能不会显示-- 建议用 EXPLAIN ANALYZE(MySQL 8.0.18+)

坑 3:LIMIT 会影响执行计划

-- 有 LIMIT 和没 LIMIT,执行计划可能完全不同EXPLAINSELECT*FROMusersORDERBYcreated_at;-- 可能 filesortEXPLAINSELECT*FROMusersORDERBYcreated_atLIMIT10;-- 可能走索引

坑 4:参数化查询的坑

-- 预编译语句可能用错误的执行计划-- 因为第一次执行的参数决定了计划-- 可以用 FORCE INDEX 或优化器提示

七、实战技巧总结

技巧 1:快速定位慢查询

-- 开启慢查询日志SETGLOBALslow_query_log='ON';SETGLOBALlong_query_time=1;-- 超过 1 秒就记录-- 然后用 EXPLAIN 分析这些 SQL

技巧 2:对比优化前后

-- 优化前保存执行计划EXPLAINSELECT...\G-- \G 竖排显示,好复制-- 优化后对比关键指标:type、key、rows、Extra

技巧 3:用 optimizer_trace 看详细决策过程

-- MySQL 深度调试SETSESSIONoptimizer_trace="enabled=on";SELECT*FROMinformation_schema.OPTIMIZER_TRACE;

技巧 4:PostgreSQL 的可视化神器

-- 生成 JSON 后,可以用 https://explain.dalibo.com/ 可视化EXPLAIN(FORMAT JSON,ANALYZE,BUFFERS)SELECT*FROMusers;

八、总结

EXPLAIN 不是什么高深莫测的东西,它就是数据库给你的"执行说明书"

记住这几个核心要点:

  1. type看访问方式—— ALL 是红灯,ref 是绿灯
  2. key看用没用索引—— NULL 就是没用,要排查
  3. rows看扫描量—— 越小越好,上万要警惕
  4. Extra看额外操作—— filesort、temporary 是性能杀手

不同数据库的 EXPLAIN 大同小异:

  • MySQL:表格直观,重点关注 type 和 Extra
  • PostgreSQL:树形结构,cost 和 actual time 很有用
  • Oracle:成本绝对值最准,企业级功能最全
  • SQL Server:图形化最友好,SSMS 无敌

写在最后

说实话,我刚工作那会儿也觉得 EXPLAIN 输出密密麻麻的,看着头大。

但踩了几次坑之后发现——这玩意儿就是数据库优化的导航仪,不会用的话,优化 SQL 就像闭着眼睛开车。

现在我已经养成习惯了:任何线上 SQL 改动,必须先 EXPLAIN 确认执行计划没问题。

你在实际项目中有没有被执行计划坑过?或者有什么 EXPLAIN 的高级玩法?欢迎在评论区交流!


本文基于 MySQL 8.0、PostgreSQL 15、Oracle 19c、SQL Server 2019 整理,不同版本可能存在差异。

http://www.jsqmd.com/news/785508/

相关文章:

  • Positive AI:从功能驱动到福祉驱动的AI设计范式与实践
  • CANN/tensorflow安全声明
  • 别再喊 PG 完爆 MySQL 了:阿里京东美团业务库都用 MySQL,不是他们没看 PG
  • ESP32-S3驱动ST7735彩屏:从零到亮的保姆级配置指南(附完整接线图)
  • CANN/sip交换向量示例
  • 第 4 章:模块与包管理
  • 量子计算动态解耦技术:原理、实现与应用
  • 基于Playwright的浏览器自动化技能库:从模块化封装到实战应用
  • 开源OSINT工具iGotcha:模块化数字痕迹追踪与信息聚合实战
  • 大模型评测中的多样性挑战:从标准化基准到公平评估的实践路径
  • AI技术博客实战:从资讯编译到深度文章的全流程解析
  • 告别点灯调试:用Arduino和TM1629A快速搭建一个多功能显示仪表盘
  • C++学习(26_05_09)
  • 对比自行维护Taotoken在稳定性与成本上的优势感知
  • 港风滤镜下的郑斯仁,在复古里寻找演员的多面性
  • 快速学Python编程-免费|零基础入门好处多多
  • 别再死记硬背IIC时序图了!用Arduino UNO和逻辑分析仪,5分钟带你亲手抓取波形搞懂它
  • 【Anthropic NLA 】深度拆解:自然语言自动编码器——撬开 LLM 黑箱的五把钥匙
  • 基于知识图谱与NLP的智能食谱推荐系统:从数据构建到对话引擎
  • 机器学习在生命科学中的应用:从蛋白质结构预测到单细胞分析
  • 上海外墙装饰服务商深度测评及选型指南 - 海棠依旧大
  • DownKyi视频解析引擎:B站多媒体内容获取与处理的技术架构解析
  • AI新闻周报 2026-05-04_2026-05-09
  • ceshi02ceshi03ceshi02ceshi03ceshi02ceshi03ceshi02ceshi03
  • 终极免费方案:3分钟解锁网易云音乐NCM格式,实现音乐自由
  • AI药物发现:从知识图谱到生成式化学的核心技术与实践挑战
  • 告别Webpack!用Electron Forge + Vite + Vue3从零搭建桌面应用(附完整配置流程)
  • 面试拷打:MySQL 一次批量插入多少条最优?答数字不会推导直接 -50 分
  • 2026年豆包推广优选攻略 德知域核心技术优势解析 - 打我的的
  • 3分钟终极指南:TrollInstallerX一键安装TrollStore完整教程