【MySQL从入门到精通】【高级篇】(二十三)EXPLAIN的概述与table,id字段的剖析

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 上一篇文章我们介绍了【MySQL从入门到精通】【高级篇】(二十二)慢查询日志分析,SHOW PROFILE查看SQL执行成本,这篇文章我们接着来介绍一下MySQL中一个非常重要的命令 EXPLAIN。当我们定位到查询慢的SQL之后,我们就可以使用EXPLAIN或DESCRIBE工具做针对性的分析查询语句。 DESCRIBE 语句的使用方法与EXPLAIN语句是一样的,并且分析结果也是一样的。

1. 简介

上一篇文章我们介绍了【MySQL从入门到精通】【高级篇】(二十二)慢查询日志分析,SHOW PROFILE查看SQL执行成本,这篇文章我们接着来介绍一下MySQL中一个非常重要的命令 EXPLAIN。当我们定位到查询慢的SQL之后,我们就可以使用EXPLAIN或DESCRIBE工具做针对性的分析查询语句。 DESCRIBE 语句的使用方法与EXPLAIN语句是一样的,并且分析结果也是一样的。

MySQL中有专门负责优化SELECT 语句的优化器模块,主要功能:通过分析系统中收集到的统计信息,为客户端请求的Query提供它认为最优的执行计划 (这部分最耗时)。


这个执行计划展示了接下来具体执行查询的方式,比如多表连接的顺序是什么,对于每个表采用什么访问方法来具体执行查询等等。MySQL为我们提供了EXPLAIN 语句来帮助我们查看某个查询语句的具体执行计划,大家看懂EXPLAIN 语句的各个输出项,可以针对性的提升我们查询语句的性能。

2. EXPLAIN能做什么?

表的读取顺序

数据读取操作的操作类型

哪些索引可以使用

哪些索引被实际使用

表之间的引用

每张表有多少行被优化器查询、

3. 官网介绍以及Explain的概述

MySQL的官方文档对MySQL做了一个详细的介绍。Explain的官网介绍

EXPLAIN 不仅可以作用于以SELECT 开头的查询语句,还可以作用于DELETE、INSERT、REPLACE以及UPDATE语句上。用来查看这些语句的执行计划,只是平时我们更多的用于对SELECT 语句的分析上。


需要注意的是:执行EXPLAIN时并没有真正的执行其后面的语句,因此可以安全的查看执行计划。

EXPLAIN语句输出的各个列的作用如下:

列名 描述
id 在一个大的查询语句中每个SELECT关键字都对应一个唯一的id
select_type SELECT 关键字对应的那个查询的类型
table 表名
partitions 匹配的分区信息
type 针对单表的访问方法
possible_keys 可能用到的索引
key 实际用到的索引
key_len 实际使用到的索引长度
ref 当使用索引列等值查询时,与索引列进行等值匹配的对象信息
rows 预估的需要读取的记录条数
filtered 某个表经过搜索条件过滤后剩余记录条数的百分比
Extra 一些重要的额外信息

这里先做一个整体的介绍,其中: select_typetypekeyExtra 这几列非常重要

4. 准备测试数据

4.1. 创建测试表

CREATE TABLE s1(
  id INT AUTO_INCREMENT,
  key1 VARCHAR(100),
  key2 INT,
  key3 VARCHAR(100),
  key_part1 VARCHAR(100),
  key_part2 VARCHAR(100),
  key_part3 VARCHAR(100),
  common_field VARCHAR(100),
  PRIMARY KEY(id),
  INDEX idx_key1(key1),
  UNIQUE INDEX uidx_key2(key2),
  INDEX idx_key3(key3),
  INDEX idx_key_part(key_part1,key_part2,key_part3)
) ENGINE=INNODB CHARSET=utf8;
CREATE TABLE s2(
    id INT AUTO_INCREMENT,
  key1 VARCHAR(100),
  key2 INT,
  key3 VARCHAR(100),
  key_part1 VARCHAR(100),
  key_part2 VARCHAR(100),
  key_part3 VARCHAR(100),
  common_field VARCHAR(100),
  PRIMARY KEY(id),
  INDEX idx_key1(key1),
  UNIQUE INDEX uidx_key2(key2),
  INDEX idx_key3(key3),
  INDEX idx_key_part(key_part1,key_part2,key_part3)
) ENGINE=INNODB CHARSET=utf8;

这里创建了两张一模一样的表,分别是表s1和表s2。并且在表s1中设置了主键索引id,普通索引idx_key1,唯一索引uidx_key2,以及组合索引idx_key_part。

4.2. 创建随机数函数以及存储过程

创建一个生成随机字符串的函数:

CREATE DEFINER=`baduser`@`%` FUNCTION `rand_string`(n INT) RETURNS varchar(255) CHARSET utf8 COLLATE utf8_unicode_ci
BEGIN
  DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  DECLARE return_str VARCHAR(255) DEFAULT '';
  DECLARE i INT DEFAULT 0;
  WHILE i<n DO 
   SET return_str=CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
  SET i=i+1;
  END WHILE;
  RETURN return_str;
END

创建往s1表中插入数据的存储过程:

CREATE DEFINER=`baduser`@`%` PROCEDURE `insert_s1`(IN min_num INT(10),IN max_num INT(10))
BEGIN
  DECLARE i INT DEFAULT 0;
  SET autocommit=0;
  REPEAT
  SET i=i+1;
  INSERT INTO s1 VALUES(
   (min_num+i),
  rand_string(6),
  (min_num+30*i+5),
  rand_string(6),
  rand_string(10),
   rand_string(5),
  rand_string(10),
  rand_string(10));
    UNTIL i=max_num 
    END REPEAT;
    COMMIT;
END

创建往s2表中插入数据的存储过程:

CREATE DEFINER=`baduser`@`%` PROCEDURE `insert_s2`(IN min_num INT(10),IN max_num INT(10))
BEGIN
  DECLARE i INT DEFAULT 0;
  SET autocommit=0;
  REPEAT
  SET i=i+1;
  INSERT INTO s2 VALUES(
   (min_num+i),
  rand_string(6),
  (min_num+30*i+5),
  rand_string(6),
  rand_string(10),
   rand_string(5),
  rand_string(10),
  rand_string(10));
    UNTIL i=max_num 
    END REPEAT;
    COMMIT;
END

执行存储过程

-- 调用存储过程
CALL insert_s1(10001,10000);
CALL insert_s2(10001,10000);

这里给s1表和s2表分别插入10000。执行完成之后查看下s1表中的总记录数。


5. EXPLAIN 各列作用

5.1. table

首先介绍的列是table列,无论我们的查询有多么复杂,里面包含了多少个表,到最后也需要对每个表进行单表访问的,所以MySQL规定EXPLAIN语句输出的每条记录都对应着某个单表的访问方法, 该条记录的table列代表着该表的表名(有时不是真实的表名,可能是简称)

单表查询

EXPLAIN SELECT * FROM s1;

这个语句只涉及对s1表的单表查询,所以EXPLAIN 输出中只有一条记录,其中的table列的值是s1,表明这条记录是用来说明对s1表的单表记录是用来说明对s1表的单表访问方法的。

  1. 连接查询
-- s1:驱动表 s2:被驱动表
EXPLAIN SELECT * FROM s1 INNER JOIN s2;


这条语句是s1表和s2表的关联查询,所以需要查询两张表。

在看下有临时表的情况吧

EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;

这里通过union关键字将两个查询联合起来。所以除了s1表和s2表以外,还多了一个临时表,这里的临时表的名字是<union 1,2>。

5.2 id

说完了table列,接下来说说 id列,在一个大的查询语句中每个SELECT 关键字都对应一个唯一的id。

单表查询的id列

EXPLAIN SELECT * FROM s1 WHERE key1='a';

单表查询很简单,就只有一条查询语句, 所以id值也就是1


关联查询的情况

是不是说,id值是累加的呢?多少个查询,id值就是多大?答案是否定的!!!!让我们来看下s1和s2的关联查询

EXPLAIN SELECT * FROM s1 INNER JOIN s2;

可以查看这两趟查询他们的id值是一样的,也就是说并不是多少次查询id值就累加到多少。id值一样的话可以认为是一组,从上往下顺序执行。


子查询的情况

EXPLAIN SELECT * FROM s1 WHERE key1 IN(SELECT key1 FROM s2) OR key3='a';

这里有个两个查询,一个主查询查s1表,一个子查询查s2表,按照常识我们可以知道子查询先执行,观察到子查询的id值为2。这就说明id值越大的表示越优先执行。

来看下另外一种子查询的情况

EXPLAIN SELECT * FROM s1 WHERE key1 IN(SELECT key3 FROM s2);

这里有三个查询,分别是主查询s1表,子查询s2表,以及中间表。

特殊情况说明

EXPLAIN SELECT * FROM s1 WHERE key1 IN(SELECT key2 FROM s2 WHERE common_field='a');

大家看到这sql语句猜想一下这里有几个查询,每个查询的id值是多少。如果单从sql语句出发,我们会习惯性的认为这里有两个查询,其中,一个主查询,一个子查询,子查询的id为2,主查询的id为1。那么实际情况是不是这样的呢?

很遗憾,答案是否定的!!!

这里的结果跟前面的s1和s2的关联查询结果一模一样,这就是因为 查询优化器可能对涉及子查询的查询语句进行重写,转成了多表查询的操作。

EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;

这里有三个查询,分别是驱动表s1的主查询,被驱动表s2的联合查询,以及临时表<union1,2> 这里临时表的作用是将s1和s2的查询结果去重,它不算一个表查询。

比较 UNION ALL 的使用大家就有一个清晰的认识。

EXPLAIN SELECT * FROM s1 UNION ALL SELECT * FROM s2;

由于UNION ALL 关键字没有去重的效果,所以,它不需要临时表。

小结

id 如果相同,可以认为是一组,从上往下顺序执行

在所有组中,id值越大,优先级越高,越先执行

关注点:id号每个号码,表示一趟独立的查询,一个sql的查询趟数越少越好

总结

本文对EXPLAIN命令做了一个详细的介绍,EXPLAIN 命令是分析慢查询SQL的利器,通过它我们可以窥探SQL的执行情况,从而为我们进行SQL优化提供指导意义。接着,我们详细介绍了table列和id列的含义和各种情况的说明。


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
3月前
|
存储 安全 关系型数据库
MySQL数据库约束条件概述及其重要性讨论。
正确地实现并管理好各类紧缩条件将直接影响到企业信息管理水平与服务质量,在当今大数据背景下更显得格外重要;任何设计师都需要深刻理解其原理与运作机晰承担起责任使得所托管资料安全稳固同时又具备良好伸缩灵活度迎合日益复杂商务需求变动.
154 11
|
10月前
|
SQL 关系型数据库 MySQL
网安入门之MySQL后端基础
《网安入门之MySQL后端基础》简介: 本文介绍了数据库及MySQL的基础知识,涵盖数据库的概念、结构与操作。数据库是组织化存储数据的集合,通过表、列、行等结构实现高效管理。MySQL作为开源的关系型数据库管理系统,广泛应用于Web开发。文中详细讲解了MySQL的基本操作,如增(INSERT)、删(DELETE)、改(UPDATE)、查(SELECT)等语句的使用方法,并介绍了数据库事务的ACID特性。此外,还探讨了SQL注入攻击的风险及防范措施,强调了预处理语句的重要性。最后,简述了PHP中mysqli扩展的使用方法,包括连接数据库、执行查询和关闭连接等步骤。
|
11月前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
2336 10
|
SQL 关系型数据库 MySQL
mysql主从复制概述和配置
【10月更文挑战第22天】MySQL 主从复制是一种将主服务器的数据复制到一个或多个从服务器的技术,实现读写分离,提高系统性能和可用性。主服务器记录变更日志,从服务器通过 I/O 和 SQL 线程读取并应用这些变更。适用于读写分离、数据备份和恢复、数据分析等场景。配置步骤包括修改配置文件、创建复制用户、配置从服务器连接主服务器并启动复制进程。
394 1
|
5月前
|
关系型数据库 MySQL
MySQL数据表添加字段(三种方式)
本文解析了数据表的基本概念及字段添加方法。在数据表中,字段是纵向列结构,记录为横向行数据。MySQL通过`ALTER TABLE`指令支持三种字段添加方式:1) 末尾追加字段,直接使用`ADD`语句;2) 首列插入字段,通过`FIRST`关键字实现;3) 指定位置插入字段,利用`AFTER`指定目标字段。文内结合`student`表实例详细演示了每种方法的操作步骤与结构验证,便于理解与实践。
|
11月前
|
关系型数据库 MySQL 数据库
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
在这一章节,主要介绍两个部分,数据库相关概念及MySQL数据库的介绍、下载、安装、启动及连接。接着,详细描述了MySQL 8.0的版本选择与下载,推荐使用社区版(免费)。安装过程包括自定义安装路径、配置环境变量、启动和停止服务、以及客户端连接测试。此外,还提供了在同一台电脑上安装多个MySQL版本的方法及卸载步骤。最后,解释了关系型数据库(RDBMS)的特点,即基于二维表存储数据,使用SQL语言进行操作,格式统一且便于维护。通过具体的结构图展示了MySQL的数据模型,说明了数据库服务器、数据库、表和记录之间的层次关系。
1928 56
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
|
8月前
|
人工智能 关系型数据库 MySQL
解决MySQL自增id用尽的问题
本文介绍了解决文章点击记录表(`article_click_record`)数据量激增问题的方案。由于用户量大,每天新增约400万条记录,导致表id接近溢出(2,100,000,000),且占用空间超320G。解决方案包括:1) 新建`article_click_record_new`表,将id类型改为BIGINT以避免溢出;2) 过渡阶段同时写入新旧表,待旧表id溢出后切换至新表;3) 定时清理过期数据或转移旧表内容。实现方式涉及修改相关接口和服务逻辑,确保业务平稳过渡。
191 5
|
11月前
|
存储 关系型数据库 MySQL
MySQL主键谁与争锋:MySQL为何钟爱自增主键ID+UUID?
本文深入探讨了在MySQL中使用自增类型主键的优势与局限性。自增主键通过保证数据的有序性和减少索引维护成本,提升了查询和插入性能,简化了数据库管理和维护,并提高了数据一致性。然而,在某些业务场景下,如跨表唯一性需求或分布式系统中,自增主键可能无法满足要求,且存在主键值易预测的安全风险。因此,选择主键类型时需综合考虑业务需求和应用场景。
382 2
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
253 8
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
555 3

推荐镜像

更多