让MySQL更快:EXPLAIN语句详尽解析

前言

在数据库性能调优中,SQL 查询的执行效率是影响系统整体性能的关键因素之一。MySQL 提供了强大的工具——EXPLAIN 语句,帮助开发者和数据库管理员深入分析查询的执行计划,从而发现潜在的性能瓶颈并进行针对性优化。

EXPLAIN 语句能够模拟 MySQL 优化器的执行过程,返回查询的详细执行计划,包括表的访问顺序、索引的使用情况、连接类型、扫描行数等关键信息。通过理解 EXPLAIN 的输出,开发者可以快速定位低效查询的问题所在,例如全表扫描、缺少索引、临时表或文件排序等,并采取相应的优化措施。

本文将详细介绍 EXPLAIN 的基本用法、输出字段的含义,并通过实际案例演示如何利用 EXPLAIN 分析和优化 SQL 查询。

微信图片_20250524153711

一、关于EXPLAIN语句

1.1 简介

EXPLAIN 是 MySQL 提供的用于分析 SQL 查询执行计划的工具。它通过在 SELECT 语句前添加 EXPLAIN 关键字,使 MySQL 返回查询的执行计划,而不是实际执行查询。执行计划描述了 MySQL 如何访问表、如何使用索引以及如何连接表等信息。

EXPLAIN 的主要作用包括:

  • 分析查询性能:识别慢查询的根源,例如全表扫描或索引未命中。
  • 验证索引有效性:确认是否正确使用了索引,或者是否需要添加新的索引。
  • 优化查询结构:调整查询语句或表结构以提高执行效率。

1.2 语法

EXPLAIN 的基本语法如下:

EXPLAIN [EXTENDED] [FORMAT = {TRADITIONAL | JSON}] SELECT ...;  
  • EXTENDED:扩展输出,显示更多信息(如优化后的查询语句)。
  • FORMAT = JSON:以 JSON 格式返回结果,便于解析和调试。

示例

在select前加explain关键字,MySQL会返回该查询的执行计划而不是执行这条SQL

mysql> explain select * from student where id=1;
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table   | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | student | const | PRIMARY       | PRIMARY | 4       | const |    1 | NULL  |
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+
1 row in set

image

二、Explain列的含义

EXPLAIN 的输出结果包含多个字段,每个字段提供了不同的信息。以下是关键字段的详细说明:

2.1 概览

以下是 MySQL EXPLAIN输出列的详细说明,包括每列的定义、示例值、优化目标及判断标准,帮助你深入理解查询执行计划:

列名作用描述优化目标(好的输出特征)
id查询的执行顺序标识符子查询或复杂查询时,id 值高的先执行
select_type查询类型(简单查询、子查询、UNION 等)SIMPLE​ 或 PRIMARY​ 表示简单或主查询
table当前操作的表名(包括临时表或派生表)表名清晰,避免过多 <derived>​ 或 <union>
partitions匹配的分区(若表有分区)分区裁剪合理,避免全分区扫描
type数据访问方式(关键性能指标)const​、eq_ref​、ref​、range​ 优于 ALL
possible_keys可能用到的索引包含实际使用的索引
key实际使用的索引明确显示有效索引名,非 NULL
key_len索引使用的字节数与索引字段长度匹配,避免未完全使用索引
ref与索引比较的列或常量const​ 或关联字段,避免 NULL
rows预估扫描的行数(估算值)数值越小越好
filtered查询条件过滤后剩余行的百分比百分比高(接近 100%)
Extra额外执行信息(关键优化提示)出现 Using index​,避免 Using filesort

2.2 每列详细说明及优化建议

1. id

  • 含义:查询的标识符,表示查询中 SELECT​ 子句的执行顺序。
    查询的序列号,标识执行顺序。相同 id​ 按从上到下执行;不同 id​ 时,值大的先执行(如子查询)。

  • 示例

    EXPLAIN SELECT * FROM (SELECT * FROM t1) AS t_derived JOIN t2 ON t1.id = t2.id;
    
    • id=1​:派生表 t_derived​(子查询)。
    • id=1​:主查询 t2​。
  • 优化目标
    避免多层嵌套子查询(id​ 过多),减少复杂查询。

  • 单一查询(无子查询或 UNION​)时,id​ 为 1​。

  • 复杂查询中,id​ 的层级清晰,避免嵌套过深。

2. select_type

  • 含义:查询的类型,描述查询的复杂度。

  • |常见值及优化建议:|||

    说明理想情况
    SIMPLE简单查询,不包含子查询或 UNION​。最佳,避免复杂嵌套。
    PRIMARY最外层查询。正常,需关注其依赖的子查询。
    SUBQUERY子查询中的第一个 SELECT​。尽量避免,可考虑改写为连接查询。
    DEPENDENT SUBQUERY子查询依赖外部查询结果。高风险,可能导致性能下降。
    UNIONUNION​ 中的第二个或后续查询。正常,需注意 UNION​ 结果集。
    UNION RESULTUNION​ 的结果集。正常,需检查是否需要额外处理。
    DERIVED派生表(FROM​ 子句中的子查询)。需检查派生表的性能。
    MATERIALIZED物化子查询(MySQL 8.0+)。正常,但需确认物化效果。

3. table

  • 含义:当前查询涉及的表名。

  • 理想输出

    • 表名明确,避免派生表(如 <derivedN>​)或临时表(如 <union1,2>​)。
    • 若出现派生表,需检查子查询是否可优化为连接查询。

4. partitions

  • 含义:查询涉及的分区(如果表是分区表)。

    表示查询涉及的分区情况。当表是分区表时,这个列会显示匹配的分区。例如,一个表按照日期字段进行分区,查询中指定了日期范围,那么 partitions 列就会显示涉及到的分区编号或者分区名称。

  • 理想输出

    • 分区表中仅扫描相关分区(如 p1​),而非全表扫描。

    • 若为 NULL​,表示表未分区或未使用分区。

      如果表是分区表,希望 partitions 列显示的分区范围尽量小。这样可以减少查询需要扫描的数据量,提高查询效率。例如,如果一个分区表有 100 个分区,而查询只涉及到其中的 1 - 2 个分区,这就是比较理想的输出。

5. type

  • 含义:连接类型(访问方法),反映 MySQL 如何查找表中的行。

  • 性能排序(从优到劣)

    1. system:表仅一行(系统表),是 const​ 的特例。
    2. const:通过主键或唯一索引等值查询,最多匹配一行。
    3. eq_ref:使用主键或唯一索引进行等值连接(如 JOIN​)。
    4. ref:使用非唯一索引进行等值查询。
    5. range:索引范围查询(如 BETWEEN​、>​、<​)。
    6. index:全索引扫描(比全表扫描快)。
    7. ALL:全表扫描(最差)。
  • 优化建议

    • 目标是达到 const​、eq_ref​ 或 ref​。
    • 避免 ALL​,需添加索引或优化查询条件。

6. possible_keys

  • 含义:可能使用的索引(候选索引)。

  • 理想输出

    • 显示多个候选索引(说明索引设计合理)。

    • 若为 NULL​,表示无可用索引,需添加索引。

      列出与查询条件相关的索引。

7. key

  • 含义:实际使用的索引。如果 key​ 为 NULL​,表示没有使用索引,可能是全表扫描。

  • 理想输出

    • 明确显示使用的索引(如 idx_name​)。
    • 若为 NULL​,表示未使用索引,需检查 possible_keys​ 并优化索引。
    • 显示与 possible_keys​ 中相同的索引,说明 MySQL 选择了合适的索引。

8. key_len

  • 含义:使用的索引长度(字节数)。

  • 理想输出

    • 值越小越好(表示使用的索引列越少或数据类型更紧凑)。
    • 例如,VARCHAR(100)​ 使用 utf8mb4​ 编码时,最大占用 400​ 字节。

9. ref

  • 含义:显示索引的哪一列被使用,以及与之比较的值(常量或列名)。

    • 显示哪些列或常量被用于查找索引列上的值。常见值包括:

    const​:使用常量值。

    表的列名:使用其他表的列进行比较。

  • func​:使用函数结果。

  • 理想输出

    • 显示具体的列名或常量(如 const​),表明索引有效。
    • 若为 func​ 或 NULL​,可能表示索引未正确使用。
    • 显示具体的列名或常量,表明索引被有效利用。

10. rows(估计扫描行数)

  • 含义:MySQL 估计需要扫描的行数。

  • 理想输出

    • 值越小越好(表示过滤条件越精确)。例如,如果一个查询估算只需要检查 10 行就可以得到结果,这比估算检查 10000 行要好得多。这表明查询能够快速定位到所需的数据行。
    • 若值过大(如 100000​),需优化索引或查询条件。

11. filtered

  • 含义:表示查询条件过滤的行百分比(MySQL 5.7+)。该值表示查询扫描的行中有多少被筛选掉,值的范围是 0 到 100。

    • 表示在存储引擎返回的行中,经过 MySQL 服务器层过滤后,实际满足查询条件的行的比例。它是基于表统计信息和索引统计信息的一个估算值。
  • 理想输出

    • 值越高越好(如 100%​ 表示无过滤条件)。
    • 若值较低(如 10%​),说明查询条件未充分利用索引。
    • filtered 的值应该尽可能高。例如,如果 filtered 的值是 90%,意味着存储引擎返回的行中有 90% 的行满足查询条件,这比 filtered 值为 10% 的情况要好,因为减少了不必要的数据处理。

12. Extra

  • 含义:额外信息,提供查询执行的附加说明,帮助诊断查询执行的细节
  • |常见值及优化建议:|||
    说明优化建议
    Using index使用覆盖索引(查询列全部命中索引)。无需回表,性能最佳。
    Using where使用 WHERE​ 条件过滤数据。正常,但需检查过滤条件效率。
    Using temporary需要创建临时表(如 ORDER BY​ 和 GROUP BY​ 一起使用)。避免,优化查询或添加索引。
    Using filesort需要额外排序操作(如 ORDER BY​ 未使用索引)。避免,优化排序字段索引。
    Distinct优化了 DISTINCT​ 查询。正常,无需额外优化。
    Range checked for each record未找到合适索引,需逐行检查。添加合适索引。

  • 良好输出:希望出现像 “Using index” 这样的提示,这表明查询效率较高。尽量避免出现 “Using temporary” 和 “Using filesort”,因为它们表示需要额外的资源开销来处理查询,如临时表和文件排序,这可能会降低查询性能。

三、优化建议及示例

3.1 优化建议

  1. 关注 type:确保查询达到 const​、eq_ref​ 或 ref​ 级别,避免 ALL​。
  2. 优化 Extra:避免 Using filesort​ 和 Using temporary​。
  3. 分析 key possible_keys​:确认是否使用了预期的索引。
  4. 减少扫描行数:通过索引或优化查询条件降低 rows​ 值。
  5. 检查 filtered​:确保过滤条件有效,提高查询效率。

3.2 优化示例

全表扫描

场景:全表扫描(type=ALL​)

  • 问题 SQL

    EXPLAIN SELECT * FROM users WHERE phone = '123456789';
    
  • 输出type=ALL​,key=NULL​。

  • 优化:为 phone​ 字段添加索引:

    ALTER TABLE users ADD INDEX idx_phone(phone);
    
  • 优化后输出type=ref​,key=idx_phone​,rows=1​。

多表连接优化(Using join buffer)

问题描述

多表连接时出现 Using join buffer​,性能低下。

原SQL

SELECT u.name, o.order_no 
FROM users u 
JOIN orders o ON u.id = o.user_id 
WHERE u.age > 25 AND o.status = 'completed';

EXPLAIN 分析

EXPLAIN SELECT u.name, o.order_no FROM users u JOIN orders o ON u.id = o.user_id WHERE u.age > 25 AND o.status = 'completed';

输出结果

id | select_type | table | type | possible_keys | key        | rows | Extra
---|-------------|-------|------|---------------|------------|------|-------------------
1  | SIMPLE      | u     | ALL  | idx_age       | NULL       | 1000 | Using where
1  | SIMPLE      | o     | ref  | idx_user_id   | idx_user_id| 500  | Using where; Using join buffer (Block Nested Loop)

问题诊断

  • users 表 type=ALL:未使用索引,全表扫描。
  • orders 表 Using join buffer:连接时未使用索引,性能差。

优化方案

  1. users.age创建索引

    ALTER TABLE users ADD INDEX idx_age (age);
    
  2. orders.user_id orders.status创建索引

    ALTER TABLE orders ADD INDEX idx_user_id_status (user_id, status);
    
  3. 调整查询

    SELECT u.name, o.order_no 
    FROM users u 
    JOIN orders o ON u.id = o.user_id 
    WHERE u.age > 25 AND o.status = 'completed';
    
  4. 验证优化效果

    EXPLAIN SELECT u.name, o.order_no FROM users u JOIN orders o ON u.id = o.user_id WHERE u.age > 25 AND o.status = 'completed';
    

    优化后输出

    id | select_type | table | type | possible_keys         | key                  | rows | Extra
    ---|-------------|-------|------|-----------------------|----------------------|------|---------
    1  | SIMPLE      | u     | range| idx_age               | idx_age              | 500  | Using where
    1  | SIMPLE      | o     | ref  | idx_user_id_status    | idx_user_id_status   | 200  | Using where
    

效果

  • users 表 type=range:使用索引范围扫描。
  • orders 表 Using join buffer 消失:连接直接通过索引完成。

结束语

EXPLAIN​语句是MySQL查询优化的核心工具,如同数据库工程师的"听诊器"。通过本文的详细解析,相信您已经掌握了各输出列的精髓。但需要强调的是,真正的优化功力需要在实践中不断积累。建议每次执行重要查询时养成查看执行计划的习惯,结合业务场景灵活运用索引策略、查询重写等手段。记住:优秀的数据库性能不是偶然,而是源于对每个执行细节的精心雕琢。

求点关注-gif动图 138_爱给网_aigei_com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/82442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基础 Day20

一、HashSet 集合类 1、简介 HashSet 集合底层采取哈希表存储数据 底层是HashMap 不能使存取有序 JDK8之前的哈希表是数组和链表&#xff0c;头插法 JDK8之后的哈希表是数组、链表和红黑树&#xff0c;尾插法 2、存储元素 &#xff08;1&#xff09;如果要保证元素的唯…

2505C++,32位转64位

原文 假设有个想要将一个32位值传递给一个带64位值的函数的函数.你不关心高32位的内容,因为该值是传递给回调函数的直通值,回调函数会把它截断为32位值. 因此,你都担心编译器一般生成的将32位值扩展到64位值的那条指令的性能影响. 我怀疑这条指令不是程序中的性能瓶颈. 我想出…

光伏电站及时巡检:守护清洁能源的“生命线”

在“双碳”目标驱动下&#xff0c;光伏电站作为清洁能源的主力军&#xff0c;正以年均20%以上的装机增速重塑全球能源格局。然而&#xff0c;这些遍布荒漠、屋顶的“光伏矩阵”并非一劳永逸的能源提款机&#xff0c;其稳定运行高度依赖精细化的巡检维护。山东枣庄触电事故、衢州…

C++初阶-list的使用2

目录 1.std::list::splice的使用 2.std::list::remove和std::list::remove_if的使用 2.1remove_if函数的简单介绍 基本用法 函数原型 使用函数对象作为谓词 使用普通函数作为谓词 注意事项 复杂对象示例 2.2remove与remove_if的简单使用 3.std::list::unique的使用 …

OpenHarmony平台驱动使用(一),ADC

OpenHarmony平台驱动使用&#xff08;一&#xff09; ADC 概述 功能简介 ADC&#xff08;Analog to Digital Converter&#xff09;&#xff0c;即模拟-数字转换器&#xff0c;可将模拟信号转换成对应的数字信号&#xff0c;便于存储与计算等操作。除电源线和地线之外&#…

CSS【详解】弹性布局 flex

适用场景 一维&#xff08;行或列&#xff09;布局 基本概念 包裹所有被布局元素的父元素为容器 所有被布局的元素为项目 项目的排列方向&#xff08;垂直/水平&#xff09;为主轴 与主轴垂直的方向交交叉轴 容器上启用 flex 布局 将容器的 display 样式设置为 flex 或 i…

基于MATLAB实现传统谱减法以及两种改进的谱减法(增益函数谱减法、多带谱减法)的语音增强

基于MATLAB实现传统谱减法以及两种改进的谱减法&#xff08;增益函数谱减法、多带谱减法&#xff09;的语音增强代码示例&#xff1a; 传统谱减法 function enhanced traditional_spectral_subtraction(noisy, fs, wlen, inc, NIS, a, b)% 参数说明&#xff1a;% noisy - 带…

symbol【ES6】

你一闭眼世界就黑了&#xff0c;你不是主角是什么&#xff1f; 目录 什么是Symbol&#xff1f;‌Symbol特点‌&#xff1a;创建方法&#xff1a;注意点&#xff1a;不能进行运算&#xff1a;显示调用toString() --没有意义隐式转换boolean 如果属性名冲突了怎么办&#xff1f;o…

LeetCode 649. Dota2 参议院 java题解

https://leetcode.cn/problems/dota2-senate/description/ 贪心。不会写。 class Solution {public String predictPartyVictory(String senate) {boolean rtrue,dtrue;int flag0;//flag>0,d前面有r;flag<0,r前面有dchar[] senatessenate.toCharArray();//每一轮while(r…

机器学习第二十二讲:感知机 → 模仿大脑神经元的开关系统

机器学习第二十二讲&#xff1a;感知机 → 模仿大脑神经元的开关系统 资料取自《零基础学机器学习》。 查看总目录&#xff1a;学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章&#xff1a;DeepSeek R1本地与线上满血版部署&#xff1a;超详细手把手指南 感知机详解…

maven快速上手

之前我们项目如果要用到其他额外的jar包&#xff0c;需要自己去官网下载并且导入。但是有maven后&#xff0c;直接在maven的pom.xml文件里用代码配置即可&#xff0c;配置好后maven会自动帮我们联网下载并且会自动导入该jar包 在右边的maven中&#xff0c;我们可以看到下载安装…

科学养生指南:解锁健康生活密码

健康是人生最宝贵的财富&#xff0c;在快节奏的现代生活中&#xff0c;科学养生成为保持良好状态的关键。遵循现代医学与营养学的研究成果&#xff0c;无需依赖传统中医理论&#xff0c;我们也能找到适合自己的养生之道。​ 均衡饮食是健康的基石。现代营养学强调 “食物多样&…

Qt状态机QStateMachine

QStateMachine QState 提供了一种强大且灵活的方式来表示状态机中的状态&#xff0c;通过与状态机类(QStateMachine)和转换类(QSignalTransition&#xff0c; QEventTransition)结合&#xff0c;可以实现复杂的状态逻辑和用户交互。合理使用嵌套状态机、信号转换、动作与动画、…

C++八股 —— 原子操作

文章目录 1. 什么是原子操作2. 原子操作的特点3. 原子操作的底层原理4. 内存序内存屏障 5. 原子操作和互斥锁的对比6. 常用的原子操作7. 相关问题讨论 参考&#xff1a; C atomic 原子操作_c 原子操作-CSDN博客DeepSeek 1. 什么是原子操作 原子操作&#xff08;Atomic Opera…

双紫擒龙紫紫红指标源码学习,2025升级版紫紫红指标公式-重点技术

VAR1:MA((LOWHIGHCLOSE)/3,5); VAR2:CLOSEHHV(C,4) AND REF(C,1)LLV(C,4); 双紫擒龙:REF(C,1)LLV(C,4) AND C>REF(C,2) OR REF(C,2)LLV(C,4) AND REF(C,1)<REF(C,3) AND REF(C,2)<REF(C,4) AND C>REF(C,1); VAR4:VAR1>REF(VAR1,1) AND REF(VAR1,1)<REF(VAR1,…

NeuralRecon技术详解:从单目视频中实现三维重建

引言 三维重建是计算机视觉领域中的一项关键技术&#xff0c;它能够从二维图像中恢复出三维形状和结构。随着深度学习的发展&#xff0c;基于学习的方法已经成为三维重建的主流。NeuralRecon是一种先进的三维重建方法&#xff0c;它能够从单目视频中实时生成高质量的三维模型。…

Ubuntu 上开启 SSH 服务、禁用密码登录并仅允许密钥认证

1. 安装 OpenSSH 服务 如果尚未安装 SSH 服务&#xff0c;运行以下命令&#xff1a; sudo apt update sudo apt install openssh-server2. 启动 SSH 服务并设置开机自启 sudo systemctl start ssh sudo systemctl enable ssh3. 生成 SSH 密钥对&#xff08;本地机器&#xf…

MySQL 索引的增删改查

MySQL 索引的增删改查 1 建表时创建索引 [UNIQUE|FULLTEXT|SPATIAL] INDEX|KEY [别名] (字段名 [(长度)] [ASC|DESC] )主键直接写&#xff1a; PRIMARY KEY (Id)例如&#xff1a; CREATE TABLE people (id int NOT NULL PRIMARY KEY AUTO_INCREMENT,last_name varchar(10)…

为什么现代CSS应该选择OKLCH:从颜色科学到设计系统革新

在数字界面中&#xff0c;颜色不仅是美学的载体&#xff0c;更是信息传递的重要工具。CSS Color Level 4 标准引入了 OKLCH 颜色空间, 提供​​感知均匀性​​&#xff08;颜色差异与实际视觉感受一致&#xff09;&#xff0c;解决传统HSL/HSV在调整颜色时的不自然问题。文本帮…

【java】小练习--零钱通

文章目录 前言一、项目开发流程说明二、功能实现2.1 菜单2.2 零钱通明细2.3 零钱通收益2.4 零钱通消费2.5 零钱通退出确认2.6 零钱通金额校验2.7 完整代码 三、零钱通OOP版 前言 本文是我跟着B站韩顺平老师的 Java 教程学习时动手实现“零钱通”项目的学习笔记&#xff0c;主要…