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变化

相关推荐
一方~30 分钟前
XML语言
xml·java·web
LSL666_31 分钟前
Java——多态
java·开发语言·多态·内存图
麓殇⊙34 分钟前
CurrentHashMap的整体系统介绍及Java内存模型(JVM)介绍
java·开发语言·jvm
豌豆花下猫1 小时前
Python 3.14 新特性盘点,更新了些什么?
后端·python·ai
flying_13141 小时前
面试常问系列(一)-神经网络参数初始化-之-softmax
深度学习·神经网络·算法·机器学习·面试
Python私教1 小时前
Python函数:从基础到进阶的完整指南
java·服务器·python
rit84324991 小时前
Java中的分布式缓存与Memcached集成实战
java·分布式·缓存
LSL666_1 小时前
Java——包装类
java·开发语言·包装类
caihuayuan51 小时前
Vue生命周期&脚手架工程&Element-UI
java·大数据·spring boot·后端·课程设计
故事很腻i2 小时前
RabbitMQ 消息不重复消费和顺序性
java·rabbitmq