【第16天】SQL进阶-查询优化一定要学EXPALIN (SQL 小虚竹)

举报
小虚竹 发表于 2022/10/06 09:23:24 2022/10/06
【摘要】 回城传送–》《32天SQL筑基》 零、前言​ 我的学习策略很简单,题海策略+ 费曼学习法。如果能把这些题都认认真真自己实现一遍,那意味着 SQL 已经筑基成功了。后面的进阶学习,可以继续跟着我,一起走向架构师之路。今天的学习内容是:SQL进阶-查询优化一定要学EXPALIN 一、练习题目题目链接难度–– 二、SQL思路 SQL进阶-查询优化一定要学EXPALIN一定要学会EXPALIN!...

回城传送–》《32天SQL筑基》

零、前言

​ 我的学习策略很简单,题海策略+ 费曼学习法。如果能把这些题都认认真真自己实现一遍,那意味着 SQL 已经筑基成功了。后面的进阶学习,可以继续跟着我,一起走向架构师之路。

今天的学习内容是:SQL进阶-查询优化一定要学EXPALIN

一、练习题目

题目链接 难度

二、SQL思路

SQL进阶-查询优化一定要学EXPALIN

一定要学会EXPALIN!
一定要学会EXPALIN!
一定要学会EXPALIN!

初始化数据

drop table if exists user_profile;
CREATE TABLE `user_profile` (
`id` int PRIMARY KEY  ,
`device_id` int NOT NULL,
`gender` varchar(14) NOT NULL,
`age` int ,
`university` varchar(32) NOT NULL,
`gpa` float);
INSERT INTO user_profile VALUES(1,2234,'male',21,'北京大学',3.2);
INSERT INTO user_profile VALUES(2,2235,'male',null,'复旦大学',3.8);
INSERT INTO user_profile VALUES(3,2236,'female',20,'复旦大学',3.5);
INSERT INTO user_profile VALUES(4,2237,'female',23,'浙江大学',3.3);
INSERT INTO user_profile VALUES(5,2238,'male',25,'复旦大学',3.1);
INSERT INTO user_profile VALUES(6,2239,'male',25,'北京大学',3.6);
INSERT INTO user_profile VALUES(7,2240,'male',null,'清华大学',3.3);
INSERT INTO user_profile VALUES(8,2241,'female',null,'北京大学',3.7);

drop table if exists question_practice_detail;
CREATE TABLE `question_practice_detail` (
`id` int NOT NULL,
`device_id` int NOT NULL,
`question_id`int NOT NULL,
`result` varchar(32) NOT NULL,
`date` date NOT NULL
);
INSERT INTO question_practice_detail VALUES(1,2234,111,'wrong','2021-05-03');
INSERT INTO question_practice_detail VALUES(2,2234,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(3,2234,113,'wrong','2021-06-15');
INSERT INTO question_practice_detail VALUES(4,2235,111,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(5,2235,115,'right','2021-08-13');
INSERT INTO question_practice_detail VALUES(6,2235,116,'right','2021-08-14');
INSERT INTO question_practice_detail VALUES(7,2236,117,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(8,2236,112,'wrong','2021-05-09');
INSERT INTO question_practice_detail VALUES(9,2236,113,'wrong','2021-08-15');
INSERT INTO question_practice_detail VALUES(10,2236,111,'right','2021-08-13');

解法

EXPALIN是什么

根据表、列、索引和WHERE子句中的条件的详细信息,MySQL 查询优化器会考虑许多技术来有效地执行 SQL 查询中涉及的查找。
可以在不读取所有行的情况下对一个巨大的表执行查询,也可以在不比较每个行组合的情况下执行涉及多个表的连接。
查询优化器选择执行最有效查询的一组操作称为“EXPALIN”

EXPALIN的用法

EXPLAIN 可与 SELECT, DELETE, INSERT, 和 UPDATE语句一起使用。

初体验:

 explain select id,device_id
from user_profile
where device_id=2240

在这里插入图片描述

输出列介绍

对EXPALIN 解释输出列简单介绍下:

名称 备注
id 查询中的一个序号id
select_type 查询中的一个类型
table 表名 当前查询(连接查询、子查询)所在的数据表
partitions 匹配的分区 如果当前数据表是分区表,则表示查询结果匹配的分区
type 联接类型 这是重要的列,显示连接使用了何种类型。结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 。一般来说,得保证查询至少达到range级别,最好能达到ref。
possible_keys 可供选择的索引 显示可能应用在这张表中的索引。如果为空,没有可能的索引。
key 实际选择的索引 如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
key_len 选择的索引长度 使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref 与索引比较的列 显示索引的哪一列被使用了
rows 估计要检查的行数 MYSQL认为必须检查的用来返回请求数据的行数
filtered 按表条件过滤的行百分比
Extra 附加信息

重要的列特别说明

id

表示SELECT语句的序列号,在EXPLAIN分析的结果信息中,有多少个SELECT语句就有多少个序列号。如果当前行的结果数据中引用了其他行的结果数据,则该值为NULL。

select_type

表示当前SQL语句的查询类型,可以表示当前SQL语句是简单查询语句还是复杂查询语句。select_type常见的取值如下:

  • SIMPLE:当前SQL语句是简单查询,不包含任何连接查询和子查询。

  • PRIMARY:主查询或者包含子查询时最外层的查询语句。

  • UNION:当前SQL语句是连接查询时,表示连接查询的第二个SELECT语句或者第二个后面的SELECT语句。

  • DEPENDENT UNION:含义与UNION几乎相同,但是DEPENDENT UNION取决于外层的查询语句。

  • UNION RESULT:表示连接查询的结果信息。

  • SUBQUERY:表示子查询中的第一个查询语句。

  • DEPENDENT SUBQUERY:含义与SUBQUERY几乎相同,但是DEPENDENT SUBQUERY取决于外层的查询语句。

  • DERIVED:表示FROM子句中的子查询。

  • MATERIALIZED:表示实例化子查询。

  • UNCACHEABLE SUBQUERY:表示不缓存子查询的结果数据,重新计算外部查询的每一行数据。

  • UNCACHEABLE UNION:表示不缓存连接查询的结果数据,每次执行连接查询时都会重新计算数据结果。

type

按从最佳到最差的顺序排列

  • system:该表只有一行(系统表)。const这是连接类型 的一个特例。
  • const:该表最多有一个匹配行,在查询开始时读取。因为只有一行,所以这一行中列的值可以被优化器的其余部分视为常量。

主键查询:
explain select id,device_id
from user_profile
where id =1

在这里插入图片描述

唯一索引查询:
创建唯一索引
CREATE UNIQUE INDEX uniq_idx_device_id ON user_profile(device_id);
explain select id,device_id
from user_profile
where device_id =2234

在这里插入图片描述

  • eq_ref:如果查询语句中的连接条件或查询条件使用了主键或者非空唯一索引包含的全部字段,则type的取值为eq_ref,典型的场景为使用“=”操作符比较带索引的列。示例: 查询有错题的用户device_id
    创建唯一索引

CREATE UNIQUE INDEX uniq_idx_device_id ON user_profile(device_id);

查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

在这里插入图片描述

explain select up.device_id
	from user_profile up
	where  up.device_id in (
	select distinct device_id
	from question_practice_detail qpd
	where qpd.result = 'wrong'
	)

在这里插入图片描述

  • ref:当查询语句中的连接条件或者查询条件使用的索引不是主键和非空唯一索引,或者只是一个索引的一部分,则type的取值为ref。示例:
    创建普通索引

CREATE INDEX idx_university ON user_profile(university);

查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

在这里插入图片描述

explain select *
from user_profile
where university='北京大学'

在这里插入图片描述

使用组合索引的一部分示例:

alter table user_profile  drop  index idx_university ;
CREATE  INDEX  idx_university_age ON user_profile(university,age);

查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

在这里插入图片描述

explain select *
from user_profile
where university='北京大学' 

在这里插入图片描述

fulltext

当查询语句中的查询条件使用了全文索引时,type的取值为fulltext
查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

创建全文索引

alter table user_profile  drop  index full_idx_university ;
CREATE FULLTEXT  INDEX  full_idx_university ON user_profile(university);

在这里插入图片描述
解析效果:

explain select *
from user_profile
where MATCH(university) AGAINST  ('北京大学' )
	

在这里插入图片描述

ref_or_null

当查询的连接条件或查询条件索引列有null时,type类型值为ref_or_null

  • 创建普通索引

alter table user_profile drop index full_idx_university;
CREATE INDEX idx_age ON user_profile(age);

  • 查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

在这里插入图片描述
解析效果:

explain select *
from user_profile
where age=20 or age is null;

在这里插入图片描述

index_merge
  • 查询语句使用索引合并优化(条件有多个索引)时,此时,key列会显示使用到的所有索引,key_len显示使用到的索引的最长键长值。
  • 查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

解析效果:

explain select *
from user_profile
where age=20 or id=6;

在这里插入图片描述

unique_subquery
  • 查询语句的查询条件为IN的语句,并且IN语句中的查询字段为数据表的主键或者非空唯一索引字段时
  • 查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

在这里插入图片描述
解析效果:

explain select qpd.*
from question_practice_detail qpd
where  qpd.device_id in (
select  up.age
from user_profile up
)

在这里插入图片描述
由于Mysql会对select进行优化,基本无法出现type为unique_subquery的场景,如果你能重现,请一定要告诉虚竹哥

index_subquery

与unique_subquery类似,但是IN语句中的查询字段为数据表中的非唯一索引字段。一样无法重现,如果你能重现,请一定要告诉虚竹哥

range
  • 当查询条件使用索引检索某个范围的数据,典型的场景为使用=、<>、>、>=、<、<=、IS [NOT] NULL、<=>、BETWEEN AND或者IN操作符时,类型为range。
  • 查看下这时候表的索引情况

SHOW INDEX FROM user_profile;
解析效果:

explain select *
from user_profile
where age<22;

在这里插入图片描述

index
  • 查询条件中的字段包含索引中的字段(含有非索引字段,就会是ALL了),此时只需要扫描索引树即可
  • 查看下这时候表的索引情况

SHOW INDEX FROM user_profile;

解析效果:

explain select age,id
from user_profile

在这里插入图片描述

  • 如果有涉及组合索引

alter table user_profile drop index idx_age ;
CREATE INDEX idx_university_age ON user_profile(university,age);

  • 查看下这时候表的索引情况

SHOW INDEX FROM user_profile;
在这里插入图片描述

解析效果:

explain select age,id
from user_profile
在这里插入图片描述
explain select university,id
from user_profile

在这里插入图片描述

ALL
  • 每次进行连接查询时,都会进行完整的表扫描。这种类型的查询性能最差
    解析效果:
explain select *
from user_profile

在这里插入图片描述

总结

一定要学会EXPALIN!
一定要学会EXPALIN!
一定要学会EXPALIN!
type的类型从最好到最差:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 。一般来说,得保证查询至少达到range级别,最好能达到ref。

参考

mysql官方文档:expalin

MySQL进阶技能树>查询优化> EXPLAIN

我是虚竹哥,我们明天见~

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。