IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> MySQL执行计划-Explain工具介绍(看了就会) -> 正文阅读

[大数据]MySQL执行计划-Explain工具介绍(看了就会)

?????

目录

1、Explain 的用途

2、explain 用法以及包含的字段

3、Explain 一图详解

4、Explain 详解(带案例-案例SQL在最后)

4.1 id 列

4.1.1 id相同

4.1.2 id不相同

4.1.3 id有相同,有不相同的?

4.2 select_type列(查询类型)

4.2.1 SIMPLE (简单查询)

4.2.2 PRIMARY (子查询中最外层的查询)

4.2.3 SUBQUERY(在select 或 where中的子查询)?

4.2.4 derived (衍生表)

4.2.5 union

4.2.6 union result?

4.3 table 列

4.4 type (访问类型)?

4.4.1 NULL

4.4.2 system

4.4.3 const

4.4.4 eq_ref

4.4.5 ref

4.4.6 ref_or_null?

4.4.7 index_merge(索引合并)?

4.4.8 range(范围索引)

4.4.9 index

4.4.10 all

4.5 possible_keys 列

4.6 key 列

4.7 key_len 列

4.8 ref列?

4.9 rows 列

4.10 extra 列

4.10.1 Using index?

4.10.2 Using where?

4.10.3 Using temporary

4.10.4 Using filesort?

4.10.5 Select tables optimized away?

4.10.6 impossible where

5、 演示数据SQL


????????explain 其实就是mysql的一个关键字,使用方法就是放在select 前使用。explain关键字可以模拟MySQL优化器执行SQL语句,可以很好的分析SQL语句活表结构的性能瓶颈。

1、Explain 的用途

  • 表的读取顺序如何
  • 数据读取操作有哪些操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间是如何引用
  • 每张表有多少行被优化器查询

2、explain 用法以及包含的字段

explain SELECT * FROM a_user WHERE id = 1;

?

执行结果有12个字段,12个字段分别是以下字段和解释:

????????id:select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序

????????select_type:查询类型

????????table:正在访问哪个表

????????partitions:匹配的分区

????????type:访问的类型

????????possible_keys:显示可能应用在这张表中的索引,一个或多个,但不一定实际使用到

????????key:实际使用到的索引,如果为NULL,则没有使用索引

????????key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度

????????ref:显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值

????????rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需读取的行数

????????filtered:查询的表行占表的百分比

????????Extra:包含不适合在其它列中显示但十分重要的额外信息

3、Explain 一图详解

4、Explain 详解(带案例-案例SQL在最后)

4.1 id 列

4.1.1 id相同

--执行顺序从上至下
explain SELECT * FROM a_user,a_user_role WHERE a_user.id = a_user_role.user_id;
-- 读取顺序:a_user > a_user_role

4.1.2 id不相同

-- 如果是子查询,id的序号会递增,id的值越大优先级越高,越先被执行
explain SELECT a_user.* FROM a_user WHERE a_user.id = (SELECT a_user_role.user_id FROM a_user_role WHERE a_user_role.role_id = 3);
-- 读取顺序:a_user_role > a_user

4.1.3 id有相同,有不相同的?

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

-- 以不同组为单位,组id值越大,优先级越高,越先执行

explain 
SELECT * FROM a_user,a_user_role WHERE a_user.id = a_user_role.user_id
union
SELECT * FROM a_user,a_user_role WHERE a_user.id = a_user_role.user_id;
-- 读取顺序:2.a_user > 2.user_role > 1.a_user > 1.user_role

4.2 select_type列(查询类型)

4.2.1 SIMPLE (简单查询)

简单查询:不包含子查询或者Union查询

EXPLAIN SELECT * FROM a_user,a_user_role WHERE a_user.id = a_user_role.user_id;

4.2.2 PRIMARY (子查询中最外层的查询)

查询中若包含任何复杂的子部分,最外层查询则被标记为主查询

explain SELECT a_user.* FROM a_user WHERE a_user.id = (SELECT a_user_role.user_id FROM a_user_role WHERE a_user_role.role_id = 3);

?

4.2.3 SUBQUERY(在select 或 where中的子查询)?

在select或where中包含子查询

explain SELECT a_user.* FROM a_user WHERE a_user.id = (SELECT a_user_role.user_id FROM a_user_role WHERE a_user_role.role_id = 3);

?

4.2.4 derived (衍生表)

????????在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中

备注:MySQL5.7+ 进行优化了,增加了derived_merge(派生合并),默认开启,可加快查询效率

-- 先关闭优化
set session optimizer_switch = 'derived_merge=off';
explain select (select 1 from a_user where id = 1) from (select * from a_user_role where id = 1) der;

-- 执行完之后再将优化开启
set session optimizer_switch = 'derived_merge=on';

?

4.2.5 union

在union中的第二个和随后的select

explain 
SELECT * FROM a_user as a_user_1
union
SELECT * FROM a_user as a_user_2
union
SELECT * FROM a_user as a_user_3;

?

4.2.6 union result?

从 union 临时表检索结果的 select

explain 
SELECT * FROM a_user as a_user_1
union
SELECT * FROM a_user as a_user_2
union
SELECT * FROM a_user as a_user_3;

?

4.3 table 列

数据来自哪张表

当?from?子句中有子查询时,table列是?<derivenN>?格式,表示当前查询依赖?id=N?的查 询,于是先执行?id=N?的查询。

当有?union?时,UNION?RESULT?的?table?列的值为<union1,2>,1和2表示参与?union?的 select?行id。

explain 
SELECT * FROM a_user as a_user_1
union
SELECT * FROM a_user as a_user_2
union
SELECT * FROM a_user as a_user_3;

4.4 type (访问类型)?

这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据行记录的大概范围。

依次从最优到最差分别为:

NULL > system > const > eq_ref > ref > ref_or_null > index_merge > range > index > ALL

一般来说,得保证查询达到range级别,最好达到ref

4.4.1 NULL

mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。

explain select min(id) from a_user;

4.4.2 system

????????表只有一行记录(等于系统表),这是const类型的特列,平时不大会出现,可以忽略

4.4.3 const

????????表示通过索引一次就找到了,const用于比较primary key或uique索引,因为只匹配一行数据,所以很快,如主键置于where列表中,MySQL就能将该查询转换为一个常量。

explain select * from a_user WHERE id = 1;

4.4.4 eq_ref

????????primary?key(主键索引)或unique?key(联合索引)索引的所有部分被连接使用,最多只会返回一条符合条件的记录。这可能是在const之外最好的联接类型了,简单的?select?查询不会出现这种type。

-- 被关联的表使用主键关联
EXPLAIN SELECT a_user_role.* FROM a_user_role left join a_user on a_user.id = a_user_role.user_id;

4.4.5 ref

????????不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。

情况1:简单的select查询,username是非唯一索引

-- 创建一个普通的索引
CREATE INDEX inx_username ON a_user (username);
explain select * from a_user where username = '王五';

情况2:联合索引

-- 创建一个联合索引
CREATE INDEX idx_user_role_id ON a_user_role (user_id,role_id);

-- 这两个sql都是ref级别,只不过使用索引的长度不同(后面详解),但是要遵守最左原则,就是 user_id一定要有
EXPLAIN select * from a_user_role WHERE user_id = 2;
EXPLAIN select * from a_user_role WHERE user_id = 2 and role_id = 2;

?

4.4.6 ref_or_null?

类似ref,不仅想找到某个索引的某个值,还想把该列的null值也找出来;

SQL后面跟着 OR 列 is null

-- username 已有索引
-- CREATE INDEX inx_username ON a_user (username);
EXPLAIN select * from a_user where username = '王五' or username is null;

4.4.7 index_merge(索引合并)?

使用了组合索引(也就是多个索引的结果集合并)

-- 下面这个sql 会被优化成走两个索引
-- select * from a_user where id = 1 和 select * from a_user where username = '王五'
EXPLAIN select * from a_user where id = 1 or username = '王五';

4.4.8 range(范围索引)

范围扫描通常出现在?in(),?between?,>?,=?等操作中。使用一个索引来检索给定范围的行。

EXPLAIN select * from a_user where id > 1;

4.4.9 index

扫描全表索引(某个索引树),这通常比ALL快一些

EXPLAIN select id from a_user;

4.4.10 all

????????即全表扫描,意味着mysql需要从头到尾去查找所需要的行。通常大部分情况下这需要增加索引来进行优化了

EXPLAIN select * from a_user;

4.5 possible_keys 列

这一列显示查询可能使用哪些索引来查找

????????explain?时可能出现?possible_keys?有列,而?key?显示?NULL?的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。

????????如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查?where?子句看是否可以创造一个适当的索引来提高查询性能,然后用?explain?查看效果

4.6 key 列

这一列显示mysql实际采用哪个索引来优化对该表的访问

如果没有使用索引,则该列是?NULL。

4.7 key_len 列

????????这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。多在复合索引中使用的比较多。

key_len计算规则如下:

  • 字符串
    • char(n):n字节长度
    • varchar(n):2字节存储字符串长度,如果是utf-8,则长度?3n+2
  • 数值类型
    • tinyint:1字节
    • smallint:2字节
    • int:4字节
    • bigint:8字节 
  • 时间类型
    • date:3字节
    • timestamp:4字节
    • datetime:8字节
  • 如果字段允许为?NULL,需要1字节记录是否为NULL。索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引

?

举例说明:

????????a_user_role 的联合索引idx_user_role_id 由 user_id 和 role_id两个bigint组成的,一个bigint占8个字节。

EXPLAIN select * from a_user_role WHERE user_id = 2;
EXPLAIN select * from a_user_role WHERE user_id = 2 and role_id = 2;

?

4.8 ref列?

????????这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名(例:id)

4.9 rows 列

????????这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数。

4.10 extra 列

????????展示额外信息,但是十分重要

4.10.1 Using index?

使用覆盖索引,查询结果就是索引所在列,避免访问了表的数据行。

EXPLAIN select id from a_user WHERE id = 2;

4.10.2 Using where?

使用where语句来处理结果,本人理解为,查询条件没有走索引或者是没有索引。

DROP INDEX inx_username ON a_user;
EXPLAIN select * from a_user WHERE username = '123';

CREATE INDEX inx_username ON a_user (username);

4.10.3 Using temporary

????????mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。

-- 先删除表中的索引
-- DROP INDEX <索引名> ON <表名>

DROP INDEX inx_username ON a_user;
explain SELECT distinct username from a_user;

-- 再将索引添加回来
CREATE INDEX inx_username ON a_user (username);
explain SELECT distinct username from a_user;

4.10.4 Using filesort?

????????将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况下一般也是要考虑使用索引来优化的。

?

a_user.username未创建索引,会浏览a_user整个表,保存排序关键字username和对应的id,然后排序username并检索行记录

-- 删除索引
DROP INDEX inx_username ON a_user;
-- 根据 username排序
explain SELECT id,username from a_user order by username;

-- 将索引添加回来
CREATE INDEX inx_username ON a_user (username);

4.10.5 Select tables optimized away?

使用某些聚合函数(比如?max、min)来访问存在索引的某个字段

explain select min(id) from a_user;

4.10.6 impossible where

where子句的值总是false,不能用来获取任何数据。

explain select * from a_user WHERE username = '张三' and username = '李四';

5、 演示数据SQL

CREATE TABLE `a_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(50) DEFAULT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '密码',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户表';


CREATE TABLE `a_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(20) NOT NULL COMMENT '角色名称',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='角色';

CREATE TABLE `a_user_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `user_id` bigint(20) NOT NULL COMMENT '用户id',
  `role_id` bigint(20) NOT NULL COMMENT '角色id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户权限表';

INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (1, '张三', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (2, '李四', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (3, '王五', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (4, '王五', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (5, '15010480559', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (6, 'liulongying', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (7, 'dutianyu', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (8, 'zhuyanlin', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (9, NULL, '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (10, 'admin', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (11, 'guodianwei', '$2a$10$VwWK1zPdf6asro8rhEGKK.JCHYixjNi500sXQJQb15eRGF9xilxmW');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (12, 'zhaozhengxing1111', '$2a$10$EZCI.Ysb7hWhUQ.aYZqpK.Mg5VWg/99eU1ldheTR/seGRolXoqudO');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (13, 'jianghongyu', '$2a$10$XGfOgLOUN9urcbVmK4XuXuv.hipxfmaEhEGibZkZXhmbh4r/eFAdO');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (14, 'cuiqingqing', '$2a$10$DEZPRouyJqZAVG2qHnPMMeH6ztfPAF7nhIQTaTg63hZ5.5//F/cXO');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (15, 'hepengcong', '$2a$10$a/DWtXdHFoMdSm1V2LCPvuTH3qBe0tfTOdFa26EVl1whghnCpgzFy');
INSERT INTO `a_user`(`id`, `username`, `password`) VALUES (16, 'jianghongyu1', '$2a$10$XG');

INSERT INTO `a_role`(`id`, `name`) VALUES (1, '管理员');
INSERT INTO `a_role`(`id`, `name`) VALUES (2, '子管理员');
INSERT INTO `a_role`(`id`, `name`) VALUES (3, '部长');
INSERT INTO `a_role`(`id`, `name`) VALUES (4, '组长');

INSERT INTO `a_user_role`(`id`, `user_id`, `role_id`) VALUES (1, 1, 1);
INSERT INTO `a_user_role`(`id`, `user_id`, `role_id`) VALUES (2, 1, 2);
INSERT INTO `a_user_role`(`id`, `user_id`, `role_id`) VALUES (3, 2, 3);
INSERT INTO `a_user_role`(`id`, `user_id`, `role_id`) VALUES (5, 2, 4);
INSERT INTO `a_user_role`(`id`, `user_id`, `role_id`) VALUES (4, 3, 4);

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:35:41  更:2022-09-21 00:39:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:32:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码