mysql-EXPLAIN执行计划分析

知其然要知其所以然,探索每一个知识点背后的意义,你知道的越多,你不知道的越多,一起学习,一起进步,如果文章感觉对您有用的话,关注、收藏、点赞,有困惑的地方请评论,我们一起交流!

MySQL 执行计划深度分析指南


一、执行计划核心字段解析

通过 EXPLAIN 输出的每个字段都暗藏优化线索:

字段 核心意义 优化方向
id 查询序列号(相同id为同一层级,不同id按序执行) 复杂嵌套查询时,观察子查询执行顺序是否合理
select_type 查询类型(SIMPLE/PRIMARY/SUBQUERY/DERIVED/UNION等) DERIVED(派生表)考虑是否可用物化视图替代;UNION RESULT关注临时表性能
partitions 匹配的分区(仅分区表有效) 验证分区裁剪是否生效,避免扫描多余分区
type 访问类型(性能排序:system > const > eq_ref > ref > range > index > ALL 目标是将type提升至range及以上,避免ALL全表扫描
possible_keys 可能使用的索引 若列出的索引未被使用,需检查索引失效原因
key 实际使用的索引 强制使用索引:FORCE INDEX;忽略索引:IGNORE INDEX
key_len 索引使用的字节数 计算复合索引实际使用长度,判断是否达到最左前缀要求
ref 索引匹配的列或常量 const表示常量引用;列名表示关联字段
rows 预估扫描行数(InnoDB统计信息) 对比rows与真实行数的偏差,过大时需ANALYZE TABLE更新统计信息
filtered 存储引擎层过滤后的数据占比(0~100) 低过滤率(如<10%)考虑添加更精准的WHERE条件或覆盖索引
Extra 附加信息(Using filesort/Using temporary等) 关键优化信号源,需针对性处理

二、Type 访问类型深度剖析

  1. const/system

    • 触发条件 :通过主键或唯一索引定位单行(WHERE id = 1
    • 优化价值:性能极致,无需优化
  2. eq_ref

    • 场景:JOIN查询中,关联字段为主键或唯一索引

    • 示例

      sql 复制代码
      EXPLAIN SELECT * FROM orders 
      JOIN users ON orders.user_id = users.id; -- users.id是主键
  3. ref

    • 场景:非唯一索引等值匹配
    • 优化点
      • 联合索引需满足最左前缀
      • 区分度低的索引(如性别)可能直接全表扫描
  4. range

    • 触发操作BETWEENIN> 等范围查询

    • 索引设计

      sql 复制代码
      -- 索引 (age, city)
      WHERE age > 25 AND city = 'Beijing' -- 只能用到age列
      -- 优化:调整索引顺序为(city, age)
  5. index

    • 全索引扫描SELECT字段全在索引中,但需遍历整个索引树
    • 对比ALL的优势:索引大小通常小于表数据

三、Extra 字段关键值处理方案

Extra值 产生原因 优化策略
Using filesort 排序字段无索引或不符合索引顺序 1. 创建排序字段索引 2. 利用索引天然有序性(如时间字段)
Using temporary 使用临时表(GROUP BY/ORDER BY/DISTINCT) 1. 增加覆盖索引 2. 调大tmp_table_size 3. 避免非必要DISTINCT
Using index 覆盖索引(无需回表) 确认查询字段是否全部包含在索引中
Using where Server层对存储引擎返回的数据进行过滤 检查WHERE条件是否可以利用索引下推(ICP)
Select tables optimized away 查询可被优化为直接读取结果(如MIN/MAX使用索引) 无需优化
Using join buffer 关联字段无可用索引,使用Block Nested-Loop 1. 为关联字段添加索引 2. 调大join_buffer_size(治标不治本)

四、复杂场景执行计划分析

1. JOIN 查询优化
  • 驱动表选择原则

    • 小表驱动大表
    • 带WHERE条件的表优先作为驱动表
  • Index Nested-Loop Join

    sql 复制代码
    -- 确保被驱动表的关联字段有索引
    EXPLAIN SELECT * FROM small_table s 
    JOIN large_table l ON s.id = l.s_id; -- l.s_id需有索引
2. 子查询陷阱
  • DEPENDENT SUBQUERY (相关子查询):

    sql 复制代码
    EXPLAIN SELECT * FROM users u 
    WHERE EXISTS (
      SELECT 1 FROM orders o 
      WHERE o.user_id = u.id -- 外层依赖
    );

    优化 :改写为JOIN

    sql 复制代码
    SELECT u.* FROM users u 
    JOIN orders o ON u.id = o.user_id;
3. 索引合并(Index Merge)
  • 场景 :多个单列索引的OR组合

    sql 复制代码
    -- 索引 (a), (b)
    EXPLAIN SELECT * FROM t WHERE a = 1 OR b = 2;
    -- 出现Using union(a,b)

    风险 :合并操作消耗CPU,优先使用复合索引

    sql 复制代码
    ALTER TABLE t ADD INDEX idx_a_b (a, b);

五、高阶技巧

  1. JSON格式执行计划

    sql 复制代码
    EXPLAIN FORMAT=JSON SELECT ...
    -- 获取成本估算、触发条件等详细信息
  2. 索引选择性计算

    sql 复制代码
    SELECT 
      COUNT(DISTINCT column)/COUNT(*) AS selectivity 
    FROM table;
    -- 选择性>0.2适合建索引
  3. 执行计划可视化工具

    • MySQL Workbench Visual Explain
    • Percona Toolkit 的 pt-visual-explain

六、实战调优流程

  1. 抓取目标SQL

    • 慢查询日志
    • performance_schema.events_statements_summary_by_digest
  2. EXPLAIN解析

    • 重点关注typekey_lenrowsExtra
  3. 索引优化

    • 添加缺失索引
    • 调整索引顺序
    • 使用覆盖索引
  4. 重写SQL

    • 拆分复杂查询
    • 消除临时表/文件排序
    • 利用JOIN代替子查询
  5. 验证效果

    • 对比优化前后EXPLAIN结果
    • 监控QPS和Latency变化

相关推荐
uhakadotcom4 分钟前
Apache Camel 漏洞 CVE-2025-27636 详解与修复
后端·面试·github
uhakadotcom7 分钟前
OpenSSH CVE-2025-26466 漏洞解析与防御
后端·面试·github
uhakadotcom15 分钟前
PostgreSQL的CVE-2025-1094漏洞解析:SQL注入与元命令执行
后端·面试·github
香精煎鱼香翅捞饭21 分钟前
java通用自研接口限流组件
java·开发语言
zhuyasen22 分钟前
Go语言开发实战:app库实现多服务启动与关闭的优雅方案
后端·go
ITlinuxP27 分钟前
2025最新Postman、Apipost和Apifox API 协议与工具选择方案解析
后端·测试工具·postman·开发工具·apipost·apifox·api协议
浪遏27 分钟前
面试官😏 :文本太长,超出部分用省略号 ,怎么搞?我:🤡
前端·面试
ChinaRainbowSea39 分钟前
Linux: Centos7 Cannot find a valid baseurl for repo: base/7/x86_64 解决方案
java·linux·运维·服务器·docker·架构
囧囧 O_o40 分钟前
Java 实现 Oracle 的 MONTHS_BETWEEN 函数
java·oracle
去看日出43 分钟前
RabbitMQ消息队列中间件安装部署教程(Windows)-2025最新版详细图文教程(附所需安装包)
java·windows·中间件·消息队列·rabbitmq