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 命令输出的都是什么东西?这篇超详细! 的相关文章

  • Rails 5.2.2(活动记录)WITH 语句

    我正在使用 Rails 5 2 2 并且有一个使用 WITH 语句的复杂查询 我需要使用左外连接创建该语句 我该如何做WITH活动记录中的语句 我的 TOTAL PROFILES 由查询对象驱动 并且会发生变化 而其余部分将始终保持不变 所
  • 当子查询具有组列时,MySQL 8 不使用 INDEX

    我们刚刚从 mariadb 5 5 迁移到 MySQL 8 一些更新查询突然变得很慢 经过更多调查 我们发现当子查询有组列时 MySQL 8不使用索引 例如 下面是一个示例数据库 桌子users维护每种类型用户的当前余额 表 帐户 维护每天
  • 数据库设计 - “推”模型,或写时扇出

    背景信息 我正在尝试检索我关注的人的图像 按最新时间排序 它就像 Twitter 新闻源 显示您朋友的最新动态 Plans 目前我只需要考虑一项 那就是图像 将来我计划分析用户的行为并将他们可能喜欢的其他图像添加到他们的提要中等 http
  • 使用 Athena 从 AWS WAF 日志中的规则组列表获取终止规则

    我跟着这些说明 https docs aws amazon com athena latest ug waf logs html将我的 AWS WAF 数据放入 Athena 表中 我想查询数据以查找具有 BLOCK 操作的最新请求 此查询
  • 如何在 Elixir 的 Ecto 查询中使用“case-when”?

    我有一个 SQL 查询 例如 SELECT SUM CASE WHEN
  • 需要 SQL 选择查询帮助

    我的问题类似于SQL选择组查询 https stackoverflow com questions 11407601 sql select group query 但模式发生了变化 我想要不同的结果 如下所述 给定链接的解决方案没有给我正确
  • 动态表单字段验证的数据库设计

    在我的应用程序中 我允许用户创建一个包含他们想要的任何 HTML 表单字段 例如文本输入 文本区域 选择等 的表单 我想让用户能够为每个字段定义 0 个或多个累积验证规则 最多可能有 25 个不同的验证规则 我应该如何建模 这是一个潜在的解
  • 如何将UTF-8编码的汉字从MySql正确导出到SQL

    过去三天我们正在与严重的问题作斗争 我们从PhpmyAdmin导出MySql数据库文件 数据库条目中写入的数据是带有UTF 8字符集的中文 导出后将其转换为拉丁字符集 现在我们正在将此数据库SQl文件导入到其他主机 我们在UTF 8和排序规
  • 根据注册后的时间自动删除Wordpress用户?

    在使用用户访问管理器的基本 WordPress 3 1 设置中 是否可以自动删除 x 天前的用户 我没有找到此功能的插件 人们将如何实施这一举措 我是否能够使用 sql 或 php 查询设置一个 cron 作业 从而每天自动从数据库中删除
  • MySql 5.7 函数 UUID() 默认排序规则 - 非法混合排序规则

    Problem MySQL uuid 默认排序规则与配置连接排序规则不进行比较 我有一个使用字符集创建的数据库 表 字段 utf 8和排序规则utf8 polish ci my cnf 如下 init connect SET NAMES u
  • Node.js 将 async/await 与 mysql 一起使用

    我一直在尝试在节点中将 async await 与 MySQL 一起使用 但它每次都会返回一个未定义的值 有理由吗 请在下面找到我的代码 const mysql require promise mysql var connection co
  • PHP 和 MySql 检查表是否为空

    我有点菜鸟 而且我很难过 我需要一些代码来搜索数据库表以查找与 id 变量匹配的行 我需要抓取该表 描述 中的一个字段 如果它为空 我需要显示一条消息 如果不是另一条消息 这是我的代码 我知道我需要添加 mysqli 转义字符串 只需从内存
  • 关于数据库变更的通知

    我正在尝试一种场景 其中我想使用任何用户提交的更改来更新在不同 PC 上运行的桌面 UI 例如 Application1 安装在 PC1 PC2 和 PC3 上 假设所有 PC 都运行此应用程序 假设 PC1 上的用户 1 更改数据并提交到
  • 是否可以使用 LOAD DATA INFILE 类型命令来更新数据库中的行?

    伪表 primary key first name last name date of birth 1 John Smith 07 04 1982 眼下名包含多行的用户全名 期望的结果是分割数据 因此first name包含 John la
  • 针对 SQL Server 的 SQL 查询的执行日期时间

    我曾经发现过这个很好的查询here https dba stackexchange com a 135080 43889 我想将查询的执行时间添加到以下查询中 USE master go SELECT sdest DatabaseName
  • 对于 XML 路径:如何将属性和值保留在同一节点中

    我在使用时遇到一些问题FOR XML PATH 我的情况是 我运行了如下脚本 属性CCY和价值AMOUNT合并到同一个节点 脚本1 SELECT USD AS Amount Ccy 123000 AS Amount Foo AS Foo F
  • Mysql使用触发器建表

    我尝试在 Mysql 触发器内创建表 但没有创建 如何使用触发器创建表 这里传递的表的名称是动态的 据我所知 在触发器内创建表是不可能的 看这里 http forums mysql com read php 99 121849 122609
  • MySQL 错误 1264:列的值超出范围

    As I SETMySQL 中的 cust fax 表如下所示 cust fax integer 10 NOT NULL 然后我插入这样的值 INSERT INTO database values 3172978990 但随后它说 错误 1
  • Elastic Beanstalk 上的 Django + MySQL - 查询 MySQL 时出错

    当我在 Elastic beanstalk 上托管的 Django 应用程序上查询 MySQL 时 出现错误 错误说 admin login 处出现操作错误 1045 用户 adminDB 172 30 23 5 的访问被拒绝 使用密码 Y
  • SQL 选择另一列中具有最大值的列

    我有一个看起来像这样的表 Name Group Value A 1 0 B 1 2 C 1 5 D 2 6 E 2 0 F 3 3 我想选择每组中具有最大值的名称 例如 有 3 个组 因此结果将是 Name C because it has

随机推荐

  • 详解 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 刚来的时候还有点不适应 做了几个月之后 就变成了熟练工了 左复制 右粘贴 然后改改就是自己的代码了 生活真美好 有一天 领导说他做的有个列表页面速度很慢 半天