MySQL8 EXPLAIN 命令输出的都是什么东西?这篇超详细!

2023-11-10

引子

小扎刚毕业不久,在一家互联网公司工作,由于是新人,做的也都是简单的CRUD。刚来的时候还有点不适应,做了几个月之后,就变成了熟练工了,左复制,右粘贴,然后改改就是自己的代码了,生活真美好。

有一天,领导说他做的有个列表页面速度很慢,半天打不开,让小扎去优化下。小扎心里一惊,我都是复制别人的代码,怎么还有错?赶紧去问问同事小会,小会说:你先用EXPLAIN命令分析下SQL,看看有什么问题。

小扎赶紧用EXPLAIN命令跑了一下SQL:
在这里插入图片描述
“这些都是什么东西?”,小扎望着小会,一脸懵逼。。。“能不能给我讲讲?”

看着小扎无助的眼神,小会无奈:我仔细给你讲讲吧,你看这里的输出。。。



EXPLAIN的输出列

EXPLAIN命令用来提供MySQL的执行信息,用来显示SQL语句执行的效率,平时我们发现某条SQL语句执行慢,可以通过该语句来查看原因,看看是否用到了索引,以及其他优化措施。 EXPLAIN 可以应用在 SELECT, DELETE, INSERT, REPLACE, 和 UPDATE 语句上。

EXPLAIN命令的输出信息如下表所示:

Column JSON Name Meaning 备注
id select_id The SELECT identifier 查询语句的序号
select_type None The SELECT type 选择类型(详见下表)
table table_name The table for the output row 表名
partitions partitions The matching partitions 分区表信息,没有分区表则为NULL
type access_type The join type 连接类型(详见下表)
possible_keys possible_keys The possible indexes to choose 可供选择的索引
key key The index actually chosen 实际选择的索引
key_len key_length The length of the chosen key 选择的索引的长度
ref ref The columns compared to the index 和索引匹配的列
rows rows Estimate of rows to be examined 估算的扫描行数
filtered filtered Percentage of rows filtered by table condition 被条件过滤行数的百分比
Extra None Additional information 额外信息(详情点击超链接)

小扎,深吸一口气,怎么这复杂。。。
这还是总体上的表格,小会笑着,指着上面的 select_type(选择类型)说,你看这个select_type还可以单独细分成下面这张表格呢:



select_type(选择类型)

select_type Value JSON Name Meaning 备注
SIMPLE None Simple SELECT (not using UNION or subqueries) 简单查询(没有使用联合和子查询)
PRIMARY None Outermost SELECT 查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY
UNION None Second or later SELECT statement in a UNION UNION中第二个或后面的SELECT语句
DEPENDENT UNION dependent (true) Second or later SELECT statement in a UNION, dependent on outer query UNION中的第二个或后面的SELECT语句,取决于外面的查询
UNION RESULT union_result Result of a UNION. UNION的结果
SUBQUERY None First SELECT in subquery 子查询中的第一个SELECT
DEPENDENT SUBQUERY dependent (true) First SELECT in subquery, dependent on outer query 子查询中的第一个SELECT,取决于外面的查询
DERIVED None Derived table 派生表的SELECT
DEPENDENT DERIVED dependent (true) Derived table dependent on another table 依赖其他表的派生表的SELECT
MATERIALIZED materialized_from_subquery Materialized subquery 物化子查询
UNCACHEABLE SUBQUERY cacheable (false) A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query 不能被缓存的子查询
UNCACHEABLE UNION cacheable (false) The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) UNION中第二个或后面的不能被缓存的子查询

小扎已经开始头大了,小会说,你不用全记住,等你用到的时候,查一下表格就行,这些都是官方文档上的资料。
第一张表格中的type(连接类型),还可以细分成以下情况:



type(连接类型)

注意,以下连接类型的查询速度从快到慢排序


system

The table has only one row (= system table). This is a special case of the const join type.

当表只有一条数据的时候,是const的特例(我只有一条数据,我查找最快:)。

const

The table has at most one matching row, which is read at the start of the query. Because there is only one row, values from the column in this row can be regarded as constants by the rest of the optimizer. const tables are very fast because they are read only once.

const is used when you compare all parts of a PRIMARY KEY or UNIQUE index to constant values. In the following queries, tbl_name can be used as a const table:

通过主键或唯一索引查找,搜索结果只有一条数据,速度最快(除system外)。

// 通过主键查找
SELECT * FROM tbl_name WHERE primary_key=1;

// 通过唯一索引查找
SELECT * FROM tbl_name
  WHERE primary_key_part1=1 AND primary_key_part2=2;

eq_ref

One row is read from this table for each combination of rows from the previous tables. Other than the system and const types, this is the best possible join type. It is used when all parts of an index are used by the join and the index is a PRIMARY KEY or UNIQUE NOT NULL index.

eq_ref can be used for indexed columns that are compared using the = operator. The comparison value can be a constant or an expression that uses columns from tables that are read before this table. In the following examples, MySQL can use an eq_ref join to process ref_table:

表连接查询,主键索引或者唯一索引全部被命中,是除system和const之外,最好的连接类型,和索引列比较只能使用=号。
查询结果只有一条数据。

// 多表关联查询,单行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

// 多表关联查询,联合唯一索引,单行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

ref

All rows with matching index values are read from this table for each combination of rows from the previous tables. ref is used if the join uses only a leftmost prefix of the key or if the key is not a PRIMARY KEY or UNIQUE index (in other words, if the join cannot select a single row based on the key value). If the key that is used matches only a few rows, this is a good join type.

ref can be used for indexed columns that are compared using the = or <=> operator. In the following examples, MySQL can use a ref join to process ref_table:

使用最左前缀匹配索引(索引不是主键,也不是唯一索引),匹配到了多行数据,如果只有少量数据,性能也是不错的哦。
和索引列比较可以使用 = 或 <=> 。
查询结果有多条数据。

// 根据索引(非主键,非唯一索引),多行匹配
SELECT * FROM ref_table WHERE key_column=expr;

// 多表关联查询,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

// 多表关联查询,联合索引,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

fulltext

The join is performed using a FULLTEXT index.

使用全文索引的时候才会出现。


ref_or_null

This join type is like ref, but with the addition that MySQL does an extra search for rows that contain NULL values. This join type optimization is used most often in resolving subqueries. In the following examples, MySQL can use a ref_or_null join to process ref_table:

这个查询类型和ref很像,但是 MySQL 会做一个额外的查询,来看哪些行包含了NULL。

SELECT * FROM ref_table
  WHERE key_column=expr OR key_column IS NULL;

index_merge

This join type indicates that the Index Merge optimization is used. In this case, the key column in the output row contains a list of indexes used, and key_len contains a list of the longest key parts for the indexes used.

在一个查询里面很有多索引用被用到,可能会触发index_merge的优化机制。

unique_subquery

This type replaces eq_ref for some IN subqueries of the following form:

unique_subquery和eq_ref不一样的地方是使用了in的子查询:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

unique_subquery is just an index lookup function that replaces the subquery completely for better efficiency.

unique_subquery是一个索引查找函数,代替子查询提高效率。

index_subquery

This join type is similar to unique_subquery. It replaces IN subqueries, but it works for nonunique indexes in subqueries of the following form:

index_subquery和unique_subquery很像,区别是它在子查询里使用的是非唯一索引。

value IN (SELECT key_column FROM single_table WHERE some_expr)

range

Only rows that are in a given range are retrieved, using an index to select the rows. The key column in the output row indicates which index is used. The key_len contains the longest key part that was used. The ref column is NULL for this type.

range can be used when a key column is compared to a constant using any of the =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN() operators:

通过索引范围查找多行数据,可以使用=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, 或 IN() 操作符。

// 多行结果
SELECT * FROM tbl_name
  WHERE key_column = 10;

// 范围查找
SELECT * FROM tbl_name
  WHERE key_column BETWEEN 10 and 20;
  
// 范围查找
SELECT * FROM tbl_name
  WHERE key_column IN (10,20,30);
  
// 范围查找
SELECT * FROM tbl_name
  WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

index

The index join type is the same as ALL, except that the index tree is scanned. This occurs two ways:

If the index is a covering index for the queries and can be used to satisfy all data required from the table, only the index tree is scanned. In this case, the Extra column says Using index. An index-only scan usually is faster than ALL because the size of the index usually is smaller than the table data.

A full table scan is performed using reads from the index to look up data rows in index order. Uses index does not appear in the Extra column.

MySQL can use this join type when the query uses only columns that are part of a single index.

index类型和ALL类型一样,区别就是index类型是扫描的索引树。以下两种情况会触发:

  1. 如果索引是查询的覆盖索引,就是说查询的数据在索引中都能找到,只需扫描索引树,不需要回表查询。 在这种情况下,explain 的 Extra 列的结果是 Using index。仅索引扫描通常比ALL快,因为索引的大小通常小于表数据。

  2. 全表扫描会按索引的顺序来查找数据行。使用索引不会出现在Extra列中。

ALL

A full table scan is done for each combination of rows from the previous tables. This is normally not good if the table is the first table not marked const, and usually very bad in all other cases. Normally, you can avoid ALL by adding indexes that enable row retrieval from the table based on constant values or column values from earlier tables.

全表扫描,效率最低的查询,一般可以通过添加索引避免,这种情况是不能容忍的,赶紧优化吧。

在这里插入图片描述

type(连接类型)在图中的位置越上面越好,如果实在不行,index也是勉强可以接受的,当然ALL是不可接受的,一定要优化。

小会指着小扎的分析结果说,你看第一列的type是ALL,是最差的连接类型,后面的rows是扫描的行数,进行了全表扫描,肯定会很慢,你条件里为什么用like?
在这里插入图片描述
小扎羞愧得脸一红,我这里的代码是从别人那直接复制过来的,忘了改这里了。。。

小扎赶紧改了下SQL,重新运行:
在这里插入图片描述

“现在快多了,type是const耶,我拿到了第二名哦”,小扎对着屏幕开心得笑着。

小会仿佛看到了多年前的自己,顿时思绪万千,看着他开心的样子,微微一笑,悄悄地走开了。

参考资料:MySQl官方文档

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL8 EXPLAIN 命令输出的都是什么东西?这篇超详细! 的相关文章

  • MYSQL从每个类别中随机选择一条记录

    我有一个数据库Items表看起来像这样 id name category int 有几十万条记录 每个item可以是 7 种不同的之一categories 对应于categories table id category 我想要一个从每个类别
  • SQL 约束以防止根据列的先前值更新列

    是否可以使用检查约束 或其他一些技术 来防止在更新记录时设置与其先前值相矛盾的值 一个例子是 NULL 时间戳 表明发生了某些事情 例如 file exported 一旦文件被导出并且具有非 NULL 值 就不应再将其设置为 NULL 另一
  • MySQL 追加字符串

    How can I append a string to the end of an existing table value Let s say I have the table below And let s say that Mari
  • 通过触发器应用表的列权限

    现在 我有一个名为 Members 的表 其中包含内容 分为联系人数据 银行数据 现在 管理员应该能够创建 更新 删除用户 这些用户保存在另一个表中 该表只能访问管理员 用户应该获得自己的 mysql 用户帐户 管理员还应该能够设置权限 例
  • MySQL 转储未知选项“-no-beep”

    在旧服务器上我使用了mysql转储命令来备份 MySQL 数据库 在新服务器上 MySQL 版本为 5 6 相同的命令给出了错误 unknown option no beep 无论它插入什么 我也在互联网上搜索过 但找不到任何帮助 在 my
  • 使用加权行概率从 PostgreSQL 表中选择随机行

    输入示例 SELECT FROM test id percent 1 50 2 35 3 15 3 rows 你会如何编写这样的查询 平均 50 的时间我可以获得 id 1 的行 35 的时间 id 2 的行 15 的时间 id 3 的行
  • 如何通过SQL查询检查是否有JSON函数?

    有SQL 2016 中的 JSON 函数 https learn microsoft com en us sql t sql functions json functions transact sql例如 JSON VALUE JSON Q
  • 内部 while 循环不工作

    这是我项目网页上的代码片段 这里我想显示用户选择的类别 然后想显示属于该类别的主题 在那里 用户可以拥有多个类别 这没有问题 我可以在第一个 while 循环中打印所有这些类别 问题是当我尝试打印主题时 结果只显示一行 但每个类别中有更多主
  • SQL WHERE 取决于星期几

    我需要检查不同日期的记录 具体取决于当前是一周中的哪一天 在周五 我需要它查看整个下周 直到下周日 在其他任何一天 它都应该检查当前周 直到下周日 我目前有以下内容 但由于语法错误而无法工作 是否可以做一个CASE WHEN里面一个WHER
  • 当您在 SQL Server 中创建新登录名时,它默认选择 db_owner

    我在 SQL Server 2008 R2 中创建新的 SQL 用户时遇到一些问题 当我使用 SQL Server Management Studio 时 它会检查db owner默认情况下的角色成员资格 我只想创建一个具有只读访问权限的新
  • pip install MySQL-python 在 ubuntu 14.04 上失败,错误:命令“x86_64-linux-gnu-gcc”失败,退出状态为 1

    我已经阅读了所有要安装的软件包列表的堆栈溢出 谷歌建议 但似乎都没有解决这个问题 将 ubuntu 14 04 Web 服务器从美国托管提供商迁移到欧洲的 DigitalOcean 两者都配置了相同的 Ansible playbook 但美
  • 基于多个表的数据更新单个表 SQL Server 2005,2008

    我需要更新表one使用表中的数据two 表一和表二没有任何公共列相关 桌子three与表相关two 例如 表一 reg det 表 reg det id reg id results 101 11 344 表二 临时表 venue resu
  • 加载“mysql2”Active Record 适配器时出错

    我正在尝试升级我的应用程序 这是我在部署应用程序时遇到的错误 加载 mysql2 Active Record 适配器时出错 缺少它所依赖的宝石 无法激活mysql2 0 4 4 已经激活mysql2 0 3 21 确保所有依赖项都添加到 G
  • WHERE 值不在(子查询)

    我一直在努力解决这个问题 我有两张桌子 一张带有优惠券和发票号码的 一张带有发票号码和客户姓名的 我需要找到尚未使用优惠券的顾客 以下是表格 促销表 Promotions Invoice Coupon 1 couponA 2 couponB
  • 如何获取日期时间字段的 UTC?

    我正在使用 MySQL 5 并且正在尝试将日期时间字段转换为 UTC TIMESTAMP 这是我所拥有的 但它不起作用 并且不确定我是否可以做到这一点 但有人可以告诉我我做错了什么吗 谢谢 我已经尝试过这个 SELECT UTC TIMES
  • MySQL为每个组创建带有序列号的视图

    我在此网站上看到了类似的解决方案 但由于变量使用限制 它在视图中不可用 在MySQL中为每个组生成序列 https stackoverflow com questions 30118096 generating sequence for e
  • 同一表中同一列的 SQL 完全外连接

    这可能更多的是一个设计问题 但我希望这在没有太多巫术的情况下是可能的 假设我有一个这样的表 SELECT FROM stuff id grp 1 a 2 a 3 a 1 b 2 b 4 b 我想要得到这样的东西 ID 按列分组 a id b
  • 如何在 sql 2005 或 2008 中使列区分大小写

    是否可以根据列更改默认排序规则 我想让 1 列区分大小写 但其他所有列都不区分大小写 ALTER TABLE ALTER COLUMN允许更改单个列的排序规则 alter table Foo alter column Bar ntext c
  • Web SQL 数据库 + Javascript 循环

    我正在尝试解决这个问题 但我自己似乎无法解决 我正在使用 Web SQL DB 但无法让循环正常使用它 I use for var i 0 i lt numberofArticles 1 i db transaction function
  • PostgreSQL 位图堆扫描索引非常慢,但仅索引扫描很快

    我创建了一个包含 43kk 行的表 并用值 1 200 填充它们 因此 表中每个数字大约为 220k create table foo id integer primary key val bigint insert into foo se

随机推荐

  • 详解 Android 是如何启动的

    详解 Android 是如何启动的 2016 08 12 唐琪森 安卓开发 javascript void 0 来自 石头铺 微信号 Android Programmer 网站 www woaitqs cc 本文是 Android 系统学习
  • xilinx平台下DDR3映射为VFIFO

    FPGA开发中 数据采集 数据分析场景下需要用对高速ADC数据缓存 FPGA片内RAM无法做到大的容量 基于MIG IP做了个DDR3映射成FIFO的模块 以完成高速 量大的数据缓存应用 背景和选择 part1 官方也提供了类似功能的IP
  • makefile学习

    基本介绍 makefile编写的关键在于解决源文件的 文件依赖性 编译链接过程 源文件首先会生成中间目标文件 再由中间目标文件生成执行文件 在编译时 编译器只检测程序语法 和函数 变量是否被声明 如果函数未声明 编译器会给出一个警告 但可以
  • VS Code 打开时黑屏的恢复处理

    VS Code安装后一直黑屏的情况 一 兼容模式 Win10版本以下系统 右击VS Code打开属性窗口并在兼容性标签页内勾上以兼容模式运行这个程序 二 自动选择显卡 VS Code的渲染跟显卡设定有一定关系 打开NVIDIA控制面板 调整
  • shell脚本对硬盘进行分区——fdisk、blkid、mke2fs、mount、lsblk

    1 前言 本文介绍的是嵌入式设备烧录系统时 如何用shell脚本对硬盘进行分区 文章主要介绍的是制作烧录U盘的分区思路和关键的shell脚本语句 代码并不能直接拷贝使用 2 总体思路 1 用U盘进行系统的烧录 就是在U盘上制作一个可以运行的
  • (必备技能)使用Python实现屏幕截图

    必备技能 使用Python实现屏幕截图 文章目录 必备技能 使用Python实现屏幕截图 一 序言 二 环境配置 1 下载pyautogui包 2 下载opencv python包 3 下载PyQt5包 4 下载pypiwin32包 三 屏
  • CIFAR10数据集使用笔记

    CIFAR10数据集 1 数据集下载并转换为张量 train set torchvision datasets CIFAR10 root data path train True download True transform transf
  • JAVA语言强制类型转换要求

    JAVA语言强制类型转换要求 数据类型具有高低性的 顺序由低到高为 byte gt short gt char gt int gt long gt float gt double 1 由低到高需要强制类型转换 转换方式如下 public c
  • SIP中继对接

    freeswitch与各种设备对接的成功配置 需要的请参考 有错误的地方请指导 1 对接华为softco 中继配置 sip profiles external
  • 初探设计模式之Adapter模式

    文章目录 设计模式之Adapter模式 一 什么是Adapter模式 二 具体实例 1 使用Banner来表示高电压插座 2 使用Print来表示低电压电器 3 使用PrintBanner来表示适配器 使用的是继承 4 总体结构如下图所示
  • vivado.2019.1 安装教程

    vivado 2019 1 安装教程 下载链接 VIVADIO 2019 1 链接 https pan baidu com s 17 cPUahNzHmm 3xKsKQ7GQ 提取码 rop0 来自百度网盘超级会员V4的分享 1 解压所有文
  • JS实现随机抽奖功能

    点击开始按钮开始抽奖 div依次变红 下面是js代码 需要的自取
  • MLOps极致细节:4. MLFlow Projects 案例介绍(Gitee代码链接)

    MLOps极致细节 4 MLFlow Projects 案例介绍 Gitee代码链接 MLFlow Projects允许我们将代码及其依赖项打包为一个可以在其他平台上以可复制 reproducible 和可重用 reusable 的方式运行
  • 对称群与置换群 定义

    我刚接触抽象代数的那段时间 一直在考虑一个问题 抽象代数有什么实际应用 后来听说 群在研究一些具有对称性质的对象时有奇效 于是我试着用群去描述一些简单的几何变换 发现确实如此 这就是我在置换那篇文章的最后让大家思考等边三角形变换的原因 如果
  • C++多态概念和意义

    目录 一 什么叫重写 二 面向对象期望的重写 1 示例分析 2 所期望的重写 三 多态的概念和意义 1 多态的概念 2 C 如何支持多态概念 3 多态内部运行剖析 4 多态的意义 5 修改示例代码 四 静态联编和动态联编 五 小结 一 什么
  • DragGAN报错Setting up PyTorch plugin “bias_act_plugin“... Failed!和FAILED: bias_act.cuda.o解决办法

    问题 DragGAN终于开源了 于是下载安装结果报错了 查了一大堆资料 都没有解决办法 于是安装了个ChatGLM2 6B 在上面将自己的问题粘贴上去 给出了解决方案 结果直接解决了一天没有解决的问题 下面附上运行之后报的错误 File u
  • nestjs:改变debug端口

    目的 多个项目 如果不改调试端口 会出现无法同时调试的情况 说明 nest start debug port port 不写默认为9229
  • C++11列表初始化

    2023年7月17日 周一上午 今天在看GitHub上的源码时看到了这种用法 于是研究了一下 并把自己的研究成果记录成博客 目录 C 11为什么要推出列表初始化 举例说明 统一初始化语法 对象和容器的初始化得以用一种统一的方式来进行 防止窄
  • glsl语法整理

    glsl 语法 main 方法表示入口函数 标量 在GLSL中标量只有bool int和float三种 向量 共有vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3和bvec4九种类型
  • MySQL8 EXPLAIN 命令输出的都是什么东西?这篇超详细!

    引子 小扎刚毕业不久 在一家互联网公司工作 由于是新人 做的也都是简单的CRUD 刚来的时候还有点不适应 做了几个月之后 就变成了熟练工了 左复制 右粘贴 然后改改就是自己的代码了 生活真美好 有一天 领导说他做的有个列表页面速度很慢 半天