MySQL索引及执行计划

索引的简介

类似于一本书的目录,起到优化查询的内容

索引的分类

  • BTREE
  • RTREE
  • Hash innodb中自适应hash算法,自动维护
  • fullText:全文索引(实现和es差不多的功能,把一句话拆分成一个个词,但效果不怎么理想,因为MySQL是结构化存储,es是json格式存储)
  • Gis:地理位置索引(学的mongodb,一般存储地图)

BTREE 索引的演变

BTREE 索引原理图.png

上层节点存放下层节点的最小值,即根节点存放枝节点的最小值,枝节点存放叶子节点的最小值
BTREE+树在叶子节点增加了双向指针,BTREE*是在叶子节点和枝节点增加双向指针

辅助索引(二级索引)

1 .管理员选择一个列建立辅助索引
2 .MySQL自动将此列取出来
3 .将此列值排好序(从小到大)
4 .将排好的数据均匀的分配到叶子节点上
5 .生成枝节点和跟节点
6 .在叶子节点中的值,都会存储主键ID

聚集索引

1 .如果用的是辅助索引,拿到辅助索引叶子节点的聚集索引的ID值,去遍历,然后去查找数据
2 .MySQL会自动选择主键,作为聚集索引,没有主键会选择唯一主键,如果都没有会生成隐藏的
3 .MySQL进行存储数据时,会按照聚集索引列的值的顺序,有序的存储数据行
4 .聚集索引直接将原表数据页,作为叶子节点,然后提取聚集索引列向上生成枝节点和根节点

辅助索引细分

  • 单列辅助索引
  • 联合索引(覆盖索引)【重要】
  • 唯一索引

索引树高度问题

索引树高度一般越低越好,一般维持在3-4层最佳

数据行多的时候

采用分布式架构,进行分库分表

字段长度

尽量选择,字符串长度短的列作为索引列,如果业务不允许,则采用前缀索引

数据类型

char 和varchar的选择,enum的选择

关于索引操作的问题

查询索引

desc 表名;
PRI ===> 主键索引(聚集索引)
MUL===> 普通索引(辅助)
UNI====> 唯一索引
show index from 表名;   //查的比较全

创建索引

# 创建普通索引
alter table city add index idx_name(name)
这也是属于DDL语句,也会锁表。在业务不繁忙时间做,或者使用pt-osc工具
# 创建联合索引
alter table city add index idx_c_p(countrycode,population);
# 建立唯一索引
alter table city add index uniqe uniqx_dis(district);
注: 唯一索引列的值必须是唯一的,不能有重复值
# 建立前缀索引
alter table city add index idx_dis(district(5))

执行计划分析

作用

将优化器选择后的执行计划,给截取出来,给管理员判断执行效率。(在语句执行之前,把执行计划拿到)

获取执行计划

desc sql语句;
explain sql语句;

分析执行计划

table

表名,如果是多表连接,可能一个表出现问题,此时这个table就有作用了

type 重要

查询类型,MySQL查询中有两大类型 全表扫描和索引扫描
索引扫描的级别为: index,range,ref,eq_ref,const(system),null 从左到右的性能依次变好

  • index: 全索引扫描(整个索引列都进行遍历)desc select id from ctiy
  • range: 索引范围扫描(>,<,>=,<=,between and, in,and ,or,like)desc select id from city where id <100; desc select * from city countrycode='CHN' and countrycode='USA' like,>,<,>=,<=的性能要比and,or,between and,in 好,因为MySQL采用BTREE* 树索引,枝节点和叶子节点都有双向指针。and,or,in,between and 都用不了双向指针,一般要把and和or改写为union all对于辅助索引来说,!=和not in 不走索引,但对于主键来讲 !=和not in 等语句是走range
  • ref: 辅助索引等值查询 desc select * from city where countrycode='CHN'
  • eq_ref: 在多表连接时,子表使用主键列或唯一键作为连接条件A join B on A.x = B.y,B作为子表,B.y为主键列时,为eq_ref ,A为驱动表,是不走索引的desc select b.name,a.name,a.population from city as a join country as b on a.countrycode=b.code where a.population<100
  • const(system): 两个一样,当主键或者唯一键的等值查询时desc select * from city where id=2
  • NULL: 所查询的数据,在数据中没有时。

possible_key

可能会用到的key

key

最后用到的key

key_len

索引覆盖长度,当前列可以为空时,其中有一个字节标识是否为空

单列索引长度

注: 所有列的可以为空,utf8mb4的字符集

varchar(20) 说明

  • 能存任意20个字符
  • 不管存储的字符,数字,中文,都是1个字符最大预留长度是4字节
  • 对于中文,1个字符占4个字节
  • 对于数字和字母,1个字符实际占用大小是1个字节
  • select length(列名) from 表名 查看这一列,每行的长度
int(5)   ===>   4+1 ==》  1 为标识该列是否为空
char(2) ===> 4+4+1  ==》 1 为标识该列是否为空
varchar(2) ===> 4+4+1+1+1 ===>   1 为标识该列是否为空  其余两个1位开始位置和结束位置

联合索引

add index idx(a,b,c,d)

  • 唯一值多的列放在左侧
  • 只要我们将来的查询,所有的列都是等值查询,无关顺序排序(a,b,c,d),(b,d,c,a),(a,b,d,c)……,因为优化器自动将我们查询条件进行排序了
  • 不连续的部分条件
cda  ==> a,c,d 只走a索引,因b没有了。建立联合索引的时候是按照a,b,c,d的顺序建立的===>优化建议,可以删除原来索引,在新建一个cda的索引。(在业务支持的情况下)
所有列相同的不同的索引会相互影响。
  • 在where查询中如果出现不等值(>,<,>=,<=,like)
    add index idx(a,b,c,d)
…… where  a=1 and b>3 and c=2 and d=5   如果出现不等值查询,索引只会卡在b那,即走a和b的索引
优化建议:
1 .把不等值查询放在最后面(不过优化器会自动排序)
2 .更改联合索引的顺序,删了重新建(重点)
  • 对于多子句的情况,应用联合索引
    需要按照语句的执行顺序,建立联合索引
    为什么要用联合索引,而不是单列索引。因为MySQL默认只会使用一种索引

Extra

额外执行的命令
重点: using filesort额外的排序 ,出现此语句,说明select排序的条件列中,没有合理的用到索引,涉及到排序的条件order by,group by,distinct,union

索引的应用规范

建立索引的原则(DBA的运维规范)

  • 建表必须要有主键,一般是无关列,自增长
  • 经常为where条件列 order by,group by,join on,distinct的条件
  • 最好使用唯一值多的列,做为联合索引的最左列,其余的按照优化细节来做
  • 列值较长的索引列,我们建议使用前缀索引
  • 降低索引条目,一方面不要创建没用的索引,不常使用的索引进行清除,percona toolkit(xxx),pt-duplicate-key-checker ---检查数据库重复索引
  • 索引维护,要避开业务繁忙期
  • 小表不建索引

不走索引的情况(开发规范)

  • 没用查询条件,或者条件没用建立索引select * from city,select * from city where 1=1
  • 查询结果集是原表的绝大部分数据,应该是25%以上
  • 索引本身失效,统计数据不真实
  • 查询条件调用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,!)等
    desc select * from city where id-99=1
  • 隐式转换导致索引失效
CREATE TABLE ttt(id INT,num CHAR(2))
INSERT INTO ttt VALUES(1,2),(2,'3');
ALTER TABLE ttt ADD INDEX idx(num)
DESC SELECT * FROM ttt WHERE num=2   //不走索引
DESC SELECT * FROM ttt WHERE num='2' //走索引
num=2 ,MySQL会通过函数将2 转换为字符串类型,根据上一条,索引列有函数,将不会走索引
  • <>(相当于!),not ni 不走索引(辅助索引)
  • like '%aa' ,百分号在前面时
  • 联合索引 ???

联合索引,意外情况

将表中所有列建立联合索引,每个列作为查询条件都会走索引

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容