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

MySQL EXPLAIN 详解与优化指南

EXPLAIN 是 SQL 性能优化的关键工具,它展示了 MySQL 如何执行一条 SQL 语句。通过分析它的结果,你可以找出查询的瓶颈并进行优化。

下面我将对 EXPLAIN 进行详细解析。

一、什么是 EXPLAIN?

EXPLAIN 关键字可以放在 SELECTDELETEINSERTREPLACE 或 UPDATE 语句之前,MySQL 会返回该语句的执行计划,而不是真正执行它。

执行计划揭示了 MySQL 优化器决定如何访问表、使用哪些索引、表之间的连接方式等信息。

基本语法:

sql

EXPLAIN your_sql_statement;
-- 例如
EXPLAIN SELECT * FROM users WHERE name = 'John';

在 MySQL 8.0 之后,推荐使用 EXPLAIN FORMAT=TRADITIONAL(默认格式),或者更详细的 EXPLAIN ANALYZE(MySQL 8.0.18+ 引入,会实际执行查询并给出更精确的分析)。


二、EXPLAIN 输出列详解

执行 EXPLAIN 后,你会得到一个包含多列的结果集。以下是这些列的含义,其中前几列(type, key, rows, Extra)最为重要

列名描述重要性
id查询中每个 SELECT 子句的唯一标识符。如果相同,则按顺序执行;如果不同,id 越大优先级越高(先执行)。
select_type查询的类型,如 SIMPLE, PRIMARY, SUBQUERY, DERIVED 等。
table正在访问的表名。
partitions匹配的分区,非分区表则为 NULL。
type连接类型 或 访问类型。这是衡量查询性能的最关键指标之一。
possible_keys查询中可能用到的索引。
key查询中实际决定使用的索引。为 NULL 则表示未使用索引。
key_len使用的索引键的长度。可用于判断是否充分利用了复合索引。
ref显示索引的哪一列被使用了,通常是一个常量(const)或另一个表的列名。
rowsMySQL 估计为了找到所需的行而需要读取的行数。这个值越小越好。
filtered表示存储引擎返回的数据在服务器层过滤后,剩余多少比例满足查询条件。理想是 100。
Extra包含不适合在其他列显示的额外信息,非常多的重要信息在这里。

三、核心列深度解析

1. type(访问类型)

性能从最优到最差排序如下:

  • system > const > eq_ref > ref > range > index > ALL

  • system:表只有一行记录(等于系统表),是 const 类型的特例。

  • const:通过索引一次就找到了,用于比较 主键索引 或 唯一索引 与常数值。速度极快。

    sql

    EXPLAIN SELECT * FROM users WHERE id = 1;
    -- `id` 是主键
  • eq_ref:在连接查询时,使用 主键 或 唯一非空索引 进行关联。对于来自前表的每一行,从本表中只返回一行。这是除了 system 和 const 之外最好的连接类型。

    sql

    EXPLAIN SELECT * FROM users u 
    JOIN orders o ON u.id = o.user_id;
    -- `o.user_id` 是 `users` 表的主键 `id` 的外键,并且是唯一索引
  • ref:使用 非唯一性索引 进行扫描,返回匹配某个单独值的所有行。

    sql

    EXPLAIN SELECT * FROM users WHERE name = 'John';
    -- `name` 字段上有一个普通索引(非唯一)
  • range:只检索给定范围的行,使用一个索引来选择行。关键运算符是 BETWEEN><IN 等。

    sql

    EXPLAIN SELECT * FROM users WHERE id > 10;
    EXPLAIN SELECT * FROM users WHERE id IN (1, 2, 3);
  • index全索引扫描。遍历整个索引树来查找数据,比 ALL 快一点,因为索引文件通常比数据文件小。

    sql

    EXPLAIN SELECT id FROM users;
    -- 查询的列 `id` 正好是索引的一部分,直接从索引中读取,无需回表
  • ALL全表扫描。性能最差,意味着 MySQL 会遍历整张表来找到匹配的行。必须优化

2. rows(预估行数)

这不是查询结果的行数,而是 MySQL 为了找到目标记录,预估需要扫描多少行。这是一个基于统计信息的预估值。这个值越小越好,说明查询效率高。

3. Extra(额外信息)

这里包含大量细节,是判断查询质量的另一个关键。

  • Using index覆盖索引。查询的列都包含在索引中,无需回表查询数据行。性能极佳。

    sql

    -- 假设在 `name` 和 `age` 上有一个复合索引 (name, age)
    EXPLAIN SELECT name, age FROM users WHERE name = 'John';
  • Using where:表示在存储引擎返回行后,MySQL 服务器层再次进行了过滤。如果 type 是 ALL 或 index,并且出现 Using where,通常意味着性能不佳。

  • Using temporary:MySQL 需要创建一张临时表来处理查询。常见于 GROUP BY 和 ORDER BY 的子句涉及不同列时。需要优化

  • Using filesort:MySQL 无法使用索引对结果进行排序,需要额外的排序步骤。如果数据量大,会非常消耗资源。需要优化

  • Using join buffer:表示连接查询时,没有使用索引,需要用到连接缓冲区。通常意味着连接字段上没有索引。


四、实战分析示例

假设我们有两张表:

users 表

  • id (主键)

  • name (有普通索引)

  • email

orders 表

  • id (主键)

  • user_id (外键,关联 users.id,有索引)

  • amount

查询1:简单的等值查询

sql

EXPLAIN SELECT * FROM users WHERE name = 'Alice';

可能的结果分析:

  • typeref (使用了非唯一索引)

  • keyname (实际使用了 name 索引)

  • rows: 1 (预估扫描1行)

  • Extra: (空,或者 Using index 如果查询的列都被索引覆盖)
    结论: 这是一个高效的查询。

查询2:连接查询

sql

EXPLAIN SELECT u.name, o.amount 
FROM users u 
JOIN orders o ON u.id = o.user_id 
WHERE u.name = 'Bob';

可能的结果分析(对于 orders 表这一行):

  • typeref (使用 user_id 索引来关联)

  • keyuser_id

  • rows: 5 (预估每个用户平均有5个订单)

  • Extra: (空)
    结论: 连接效率很高,因为双方都使用了索引。

查询3:性能不佳的查询

sql

EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com' ORDER BY name;

可能的结果分析:

  • typeALL (全表扫描,因为 email 字段没有索引)

  • keyNULL

  • rows: 10000 (表中有1万行数据)

  • ExtraUsing filesort (在内存或磁盘上进行排序)
    结论: 这是一个灾难性的查询。它进行了全表扫描,并且还有一个昂贵的文件排序。
    优化建议:

  1. 为 email 字段添加索引。

  2. 如果经常需要按 name 排序,可以考虑建立 (email, name) 的复合索引,这样可以利用索引来查找和排序。


五、进阶工具:EXPLAIN ANALYZE (MySQL 8.0.18+)

EXPLAIN ANALYZE 会实际执行查询,并提供一个更详细的、包含实际执行时间的分析报告。

sql

EXPLAIN ANALYZE SELECT * FROM users WHERE name = 'John';

输出格式类似于:

text

-> Index lookup on users using idx_name (name='John')  (cost=0.35 rows=1) (actual time=0.025..0.027 rows=1 loops=1)

它提供了:

  • 实际执行时间 (actual time)。

  • 实际返回行数 (rows)。

  • 执行循环次数 (loops)。

  • 预估成本 (cost)。

这比传统的 EXPLAIN 提供了更精确的性能视图。

总结

检查点目标
type 列至少达到 range 级别,最好能到 ref。避免 ALL
key 列确保查询实际使用了合适的索引,不为 NULL
rows 列预估扫描行数尽可能小。
Extra 列追求出现 Using index。警惕 Using temporary 和 Using filesort

熟练掌握 EXPLAIN 是每个后端开发者和 DBA 的必备技能,它能帮助你从“猜测”优化变为“数据驱动”的优化。

http://www.dtcms.com/a/585466.html

相关文章:

  • ADB 无线调试 APP 完全攻略(2025 最新版)—— 从连接到查看日志,一文搞定!
  • 商家入驻网站建设免费网站怎么做
  • C语言数据结构之堆
  • VIVO算法/大模型面试题及参考答案
  • 临海网站制作好了如何上线网站开发的要求
  • KingbaseES:从MySQL兼容到权限隔离与安全增强的跨越
  • 网站改版竞品分析怎么做可以先做网站再开公司吗
  • Go语言基础:语言特性、语法基础与数据类型
  • 解决 PyQt5 中 sipPyTypeDict() 弃用警告的完整指南
  • 内网门户网站建设要求西安摩高网站建设
  • github访问响应时间过长解决
  • Spring AoP的切点匹配
  • Cookie 与 Session 全解析:从属性原理到核心逻辑,吃透 Web 状态保持
  • STM32HAL库-F1内部Flash读写操作(官网驱动)
  • 辛集建设网站网络营销推广渠道
  • 外国排版网站企业名录2019企业黄页
  • 微信小程序开发实战:图片转 Base64 全解析
  • 秒杀-订单创建消费者CreateOrderConsumer
  • 单层前馈神经网络的万能逼近定理
  • C# 如何捕获键盘按钮和组合键以及KeyPress/KeyDown/KeyUp事件之间的区别
  • Windows系统不关闭防火墙,允许某个端口的访问怎么设置?
  • UniApp 多个异步开关控制教程
  • 邯郸哪家公司做企业网站比较专业中国制造网是干什么的
  • 做视频网站把视频放在哪里wordpress建站用什么意思
  • ASP.NET Core Web 应用SQLite数据连接显示(1)
  • 网易门户网站建设网站建设及发布的流程
  • 基于python的jlink单片机自动化批量烧录工具
  • 从三路快排到内省排序:探索工业级排序算法的演进
  • CPP 学习笔记 语法总结
  • Qt 跨平台 2048 游戏开发完整教程 (含源码)