数据库运维
记录DBA学习成长历程

MySQL执行计划及索引类型

什么是执行计划?

select * from t1 where name=''zs;
分析的是优化器按照内置的cost代价计算算法,最终选择后的认为代价最小最优的执行计划。是辅助优化手段
cost就是代价成本的意思,对于计算机来说,代价是IO,CPU,内存。 
作用: 
语句执行前,先看执行计划信息,可以有效的防止性能较差的语句带来的性能问题。
如果业务中出现了慢语句,我们也需要借助此命令进行语句的评估,分析优化方案。
语句运行好坏和执行计划密切相关,执行计划分析完再让其运行,获取执行计划就是语句在执行过程中的优化器位置获取。

查看执行计划

desc select * from t_100w world.city;
explain select * from t_100w world.city;

执行计划显示结果的认识

table 此次查询涉及的表
type 查询的类型,全表扫描或者索引扫描
possiable_keys 可能会用到的索引:判断走没走索引,没用到索引的可以清除
key 之后选择使用的索引:判断走的索引是否合理
key_len 索引覆盖的长度 --判断联合索引是否合理
rows 此次查询需要扫描的行数
extra 额外的信息 

详解table

此次查询涉及到的表,针对一个查询中多个表时,精确找到问题表
desc select country.name,city.name
from city join country
on city.countrycode=country.code
where city.population='CHN';

详解type 查询类型

全表扫描:不用任何的索引ALL
索引扫描:index<range<ref<eq_ref<const(system)
至少保证range及以上索引级别

ALL

全表扫描,不走索引,需要处理
1. 查询条件列,没有索引
desc select * from t_100w where k2='34ab';
2. 查询条件出现以下语句(辅助索引列)
use world;
desc city;
desc select * from city where countrycode <> 'CHN';
desc select * from city where countrycode not in ('CHN','USA');
desc select * from city where countrycode like '%CH%';
注意:对于聚集索引列,使用这种语句,依然会走索引,早期版本也不走,新版本都走索引
desc select * from city where id <>10;

INDEX

全索引扫描,就像所有的书目录先全部看一遍
查询需要获取整个索引树中的值时:
DESC SELECT countrycode FROM city;
联合索引中,任何一个非最左列作为查询条件时:
idx_a_b_c(a,b,c) ---> a ab abc
SELECT * FROM t1 WHERE b
SELECT * FROM t1 WHERE c

RANGE

索引范围扫描
辅助配合索引>=,<=,like,in,or
1.desc SELECT * FROM city WHERE id<5;
2.desc SELECT * FROM city WHERE countrycode LIKE 'CH%';
3.desc SELECT * FROM city WHERE countrycode IN('CHN','USA');
注意:
1和2例子中,可以享受到B+树叶子节点双向指针的优势,但是3例子中是不能享受的,因为查找条件是不连续的。
所以,我们可以将3号列子改写:
DESC SELECT * FROM city WHERE countrycode='CHN'
UNION ALL
SELECT * FROM city WHERE countrycode='USA';
主键配合>,<,<>,not in

ref

非唯一性普通 
辅助索引配合等值查询
DESC SELECT * FROM city WHERE countrycode='CHN'

eq_ref

在多表连接时,非驱动表链接条件是主键或者唯一键,join连接条件使用了唯一索引(uk pK)
DESC SELECT country.name,city.name FROM city
JOIN country
ON city.countrycode=country.code
WHERE city.population <100;
因为city表的countrycode列为country表中的主键,但是city表索引类型依然是ALL

const(system)

system和const为一样的级别,是唯一索引的等值查询,聚簇索引等值查询
DESC SELECT * FROM city WHERE id=10;

NULL

不返回数据的时候性能最好
DESC SELECT * FROM city WHERE id=-10;

详解possiable_keys,key

possible_keys:可能会走的索引,所有 和此次查询有关的索引
key:此次查询选择的索引。

详解key_len

联合索引覆盖长度
对于联合索引index(a,b,c),希望将来的查询语句,对于联合索引应用的越充分越好。
key_len 可以帮助我们判断,此次查询,走了联合索引的几部分。
key_len的计算:idx(a,b,c)
select * from t1 where a= and b= and c=
key_len=a长度+b长度+c长度
长度指的是什么?
长度受到数据类型,字符集影响,指的是列的最大字节储值长度,not null为预留一个字节存字符长度
数字:tinyint存1个字节,int存4个字节,bigint存8字节
字符:utf8(utf8mb4)-->一个字符最大占3(4)个字节
           not null 没有notnull
char(10)  3*10       3*10+1
varchar(10) 3*10+2   3*10+2+1
b char(10) not null 30
b char(10) 31
c varchar(10) not null 32
c varchar(10)  33

extra 额外的信息-filesort 文件排序

using filesort:表示此次查询使用到了文件排序,说明在查询中的排序操作:order by group by distinct...
DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population; 
索引生成B树结构时,需要对整个列值进行排序,排序完落到叶子节点均匀存储show index from city;
alter table city drop index CountryCode;
alter table city add index idx_c_p(countrycode,population); 
DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population; 

结论
1.当我们看到执行计划extra位置出现filesort,说明由文件排序出现,是没有走索引的
2.观察需要排序(ORDER BY,GROUP BY ,DISTINCT )的条件,有没有索引
3. 根据子句的执行顺序,去创建联合索引,删除原来的单列索引
4.如果查询语句中包含having,则只需要给having前的条件添加联合索引,后面的order by即使添加也不走索引
解决办法:把having前面查询的值构建一个临时表(create temporary table xxxx as 分割出来的having前的语句),
having表改为where语句,然后把临时表与where后面的order by构建一个联合索引

根据业务分析哪个表和列建立什么样的索引,业务主要包括产品的功能和用户的行为,找到"热"查询语句中较慢的语句,可以通过slowlog日志工具查看。"热"数据主要看架构分布式怎么设计
开发规范:注意哪些sql语句不会走索引即使有索引也不走

explain(desc)使用场景(面试题)

题目意思: 我们公司业务慢,请你从数据库的角度分析原因

第一种情况:应急性的慢:突然夯住

应急情况:数据库夯住(卡了,资源耗尽),观察CPU,内存可以看出
处理过程:
1.show processlist; 获取到导致数据库hang的语句
主要看command列的query行,time列的运行时间长短,info列为导致数据库夯住的语句
可以用show full processlist;显示info列为导致数据库夯住的完整语句
临时解决:kill id号;
2. 根本解决问题,explain 分析SQL的执行计划,有没有走索引,索引的类型情况
3. 建索引,改语句

第二种情况:一段时间慢(持续性的):

(1)记录慢日志slowlog,分析slowlog观察时间段,
(2)explain 分析SQL的执行计划,有没有走索引,索引的类型情况
(3)建索引,改语句
赞(3)
MySQL学习笔记 » MySQL执行计划及索引类型