毁抨句 发表于 2025-6-30 22:00:53

MySQL EXPLAIN 关键字详解

​EXPLAIN 是用于分析 SQL 查询的执行计划。它能揭示 MySQL 如何执行查询(如是否使用索引、表连接顺序等),帮助我们定位性能瓶颈。
基本用法

EXPLAIN SELECT * FROM users WHERE age > 25;输出列

列名说明关键值示例id查询标识符(相同 id 表示同组查询,执行顺序从上到下;不同 id 值越大优先级越高)1(主查询)、2(子查询)select_type查询类型SIMPLE(无子查询)、PRIMARY(外层查询)、SUBQUERY(子查询)table访问的表名users、(派生表)、(UNION 结果)partitions匹配的分区p0,p1(分区表使用)type ⭐访问类型(性能核心指标,从优到劣排序)重点顺序:system > const > eq_ref > ref > range > index > ALLpossible_keys可能使用的索引idx_age(显示可选的索引名)key ⭐实际使用的索引idx_email(若为 NULL 表示未用索引)key_len索引使用的字节数4(int 索引)、152(varchar(50))ref索引匹配的列或常量const(常量)、db1.users.id(其他表的列)rows ⭐预估扫描行数(越小越好)10(理想)、10000(需优化)filtered存储引擎返回数据后在 server 层过滤的比例100.0(完全匹配)、10.0(仅 10% 数据有效)Extra ⭐额外执行信息(重要优化线索)Using index、Using temporary、Using filesort(需警惕)1、id - 查询标识符


[*]说明:
        ① 标识 SELECT 所属的查询块
        ② 相同 id 表示同一查询级别,执行顺序从上到下
        ③ 不同 id 时,值越大优先级越高(越先执行)

[*]典型值:
        ① 单查询:1
        ② 嵌套查询:1(主查询),2(子查询)
        ③ UNION:NULL(UNION 结果集)
2、select_type - 查询类型

值描述示例场景SIMPLE简单 SELECT(无子查询/UNION)SELECT * FROM usersPRIMARY最外层查询包含子查询时的外层查询SUBQUERYSELECT 中的子查询SELECT id, (SELECT name FROM profiles) FROM usersDERIVEDFROM 子句中的子查询SELECT * FROM (SELECT * FROM orders) tmpUNIONUNION 中的第二个或后续 SELECTSELECT a FROM t1 UNION SELECT b FROM t2UNION RESULTUNION 结果UNION 操作的结果集DEPENDENT SUBQUERY依赖外部查询的子查询子查询依赖外层查询结果MATERIALIZED物化子查询(MySQL 5.6+)子查询结果被物化为临时表3、table - 访问的表


[*]说明:
        ① 显示表名或别名
        ② 特殊格式:
   (1) :id=N 的派生表
   (2) :id=M 和 N UNION 的结果
   (3) :物化子查询
4、partitions - 匹配的分区


[*]说明:
        ① 对于分区表,显示查询访问的分区
        ② 非分区表始终为 NULL

[*]示例:p0,p1(访问分区 p0 和 p1)
5、type ⭐(关键性能指标)- 访问类型

说明:按性能从优到劣排序
类型描述性能示例system系统表,仅一行最优MyISAM 引擎的空表const主键/唯一索引的常量查询极优WHERE id = 1eq_refJOIN 时主键/唯一索引关联优JOIN ... ON t1.pk = t2.pkref非唯一索引的等值查询良WHERE index_col = 10fulltext全文索引中MATCH(...) AGAINST(...)ref_or_nullref + NULL 值搜索中WHERE col = 10 OR col IS NULLindex_merge索引合并优化中多个索引条件组合unique_subquery唯一索引子查询中value IN (SELECT pk FROM ...)index_subquery非唯一索引子查询中下value IN (SELECT index_col FROM ...)range索引范围扫描中下WHERE id > 10index全索引扫描差SELECT indexed_col FROM tableALL全表扫描最差无索引查询6、possible_keys - 可能使用的索引


[*]说明:
        ① 查询可能选择的索引列表
        ② NULL 表示无可用索引
        ③ 实际使用的索引可能在 key 列不同
7、key ⭐ - 实际使用的索引


[*]说明:
        ① 查询优化器最终选择的索引
        ② NULL 表示未使用索引
        ③ 可能不在 possible_keys 中(优化器选择更优索引)
8、key_len - 使用索引的长度(字节)


[*]计算规则:
        ① 数值类型:
                (1) TINYINT:1 字节
                (2) INT:4 字节
                (3) BIGINT:8 字节
        ② 字符串类型(UTF8mb4):
                (1) CHAR(10):4×10 = 40 字节
                (2) VARCHAR(10):4×10 + 长度字节(2字节)
        ③ NULL 标志:1 字节(若列可为 NULL)

[*]示例:
   ① int NOT NULL:4
   ② varchar(255) NULL:255×4 + 2 + 1 = 1023
9、ref - 索引比较的列或常量


[*]格式:
   ① const:常量值
   ② func:函数结果
   ③ db.table.column:关联表的列

[*]示例:
   ① WHERE col = 10 → const
   ② JOIN ... ON t1.id = t2.user_id → db.t2.user_id
10、rows ⭐ - 预估扫描行数


[*]说明:
        ① 存储引擎层面预估的检查行数
        ② 重要性能指标(值越小越好)
        ③ 非精确值,基于统计信息估算
11、filtered - 存储引擎返回数据的过滤百分比


[*]说明:
        ① MySQL 5.7+ 新增列
        ② 表示条件过滤后剩余数据的百分比
        ③ 计算最终行数:rows × filtered%

[*]示例:
   ① rows=1000, filtered=10.00 → 最终约 100 行
12、Extra ⭐(重要优化线索)- 附加执行信息

关键值详解:
值含义优化建议Using index覆盖索引(无需回表)优,保持Using whereServer 层过滤数据检查索引使用Using temporary使用临时表优化 GROUP BY/ORDER BYUsing filesort额外排序操作为排序字段加索引Select tables optimized away使用聚合函数优化优Using index condition索引条件下推(ICP)MySQL 5.6+ 优化特性Using join buffer使用连接缓冲区增大 join_buffer_sizeImpossible WHEREWHERE 条件永不成立查询逻辑错误Distinct优化 DISTINCT 操作-优化简单总结:


[*]优先优化 type 列:避免 ALL 和 index;
[*]检查索引使用:key 不为 NULL,且 key_len 合理;
[*]关注扫描行数:rows 值应尽可能小;
[*]警惕额外操作:Using filesort 和 Using temporary 需优化;
[*]善用覆盖索引:Using index 是最佳状态之一。
你可能发现你使用 EXPLAIN  后,输出的列只有 10 列或者 11 列,那是因为MySQL版本的缘故。小于 5.7 的版本,只会有 10 列输出。版本越高,优化升级会越多,能让我们更准确地判断索引选择和过滤效率。
乾坤未定,你我皆是黑马。-- 烟沙九洲

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: MySQL EXPLAIN 关键字详解