MySQL---DBA---肆(索引及执行计划管理)

一. 索引的作用

类似于书的目录,起到优化查询的功能

二. 索引类型

  1. B树索引:BTREE
  2. R树索引:RTREE
  3. HASH索引
  4. 全文索引

三. BTREE索引细分类(算法)

3.1 B-TREE

普通索引,现在基本不适用,由根节点,枝节点,叶节点三部分组成,顺序由根到叶依次往下查询,每次都要从新查询一遍,不包括范围查询

3.2 B+TREE

和B-TREE组成结构一样,但是此索引在叶节点部分增加了左右双向的范围查询方式

3.3 B*TREE

是现在mysql数据库默认的查询方式,也是目前最通用的,组成与上述一样,但是此索引在B+TREE的基础上在枝节点增加了左右双向的范围查询方式(有时也被称为B+TREE,归位了一类)

MySQL---DBA---肆(索引及执行计划管理)_第1张图片
image.png

四. BTREE索引的功能分类

  • 聚集索引(集群索引)
  • 辅助索引(二级索引)

五. BTREE索引是如何构建的

5.1 索引构建BTREE结构过程

1. 索引是基于表中,列(索引键)的值生成的B树结构
2. 首先提取此列的所有值,进行自动排序
3. 将排好序的值均匀分布到索引树的叶子节点中(16k)
4. 依次生成枝节点与根节点,根据数据量级和索引键长度,生成合适的索引树高度

5.2 辅助索引(s)构建B树结构的过程

1. 从表中的列中提取此列的所有值,进行自动排序
2. 将排好序的值,均匀分布到索引树的叶子节点(16k)
3. 生成此索引键指向对应的后端数据页(整行数据)的指针
4. 生成枝节点和根节点,根据数据量级和索引键长度,生成合适的索引树高度
---
  辅助索引会发生跳跃状态查找,无序的查找,辅助索引的(叶节点)存储的是索引键所对应的整列数
据的值与指向此行整个数据的一个指向信息。而(枝节点)与(根节点)存储的是索引键下所对应数据
的值的信息。查找顺序由根---枝---叶依次查找。一般配合聚集索引使用

5.3 聚集索引(c)构建B树结构的过程

1. 默认按照主键列(ID列)生成聚集索引;如果没有主键的情况下存储引擎会使用唯一键;如果都没有
则会自动生成隐藏的聚集索引   #注意:主键列是前提,一般建表时都会构建
2. 聚集索引在存储数据时就会按照其主键列(ID列)的顺序存储到磁盘的数据页(我们称之为聚集索引组织表)
3. 因为它本身已经排序,所以构建B树结构时不用再次排序
4. 将排好序的整行数据生成叶子节点,可以理解为磁盘的数据页就是叶子节点
5. 枝节点与根节点依次调用下层节点主键的最小值(16k)
---
  聚集索引的叶子节点把其对应的整行数据进行存储,可以直接获取到整行数据信息,所以不需要指向。
大小为16kb,而聚集索引的枝节点与根节点存储的确实下层节点主键的最小值(方便存储,不占用太大空
间)大小都为16kb,查找顺序由根---枝---叶进行依次查找,到叶子节点时可以直接获取到此行所有数据

5.4 辅助索引和聚集索引区别

辅助索引:
1. 叶子节点只保存主键值+索引键值的有序存储以及指向信息
2. 对索引键值会自动排序
3. 需要手动进行创建
4. 辅助索引可以有多个
5. 任何列都可以创建辅助索引

聚集索引:
1. 只能在主键列生成,唯一且非空
2. 数据存储时,就是按照(主键列)聚集索引顺序进行有序存储
3. 叶子节点保存的是整个有序的数据行
4. 叶子节点不需要单独生成
MySQL---DBA---肆(索引及执行计划管理)_第2张图片
image.png

六. 辅助索引细分

6.1 单列辅助索引

  • select * from t1 where name=' ';

6.2 多列辅助索引(联合索引)

  • select * from t1 where a and b and c;

6.3 唯一索引

  • 索引键值唯一的列进行索引创建

七. 索引树高度原因(影响IO,越低越好)

7.1 数据量级过大

解决:

  • (1)分区表解决---把数据分开放到同一台服务器上,对服务器压力过大
  • (2)分库分表---目前普遍的分布式架构,分开数据到不同的服务器上,减轻单台服务器压力

7.2 索引键值长度过长

解决:

  • 尽可能选择列值短的列创建索引
  • 采用浅醉创建索引

7.3 数据类型不同(索引键值长度不一,比如name)

解决:

  • 选择合适的数据类型(char,varchar,enum...)

八. 索引的基本管理

8.1 索引管理命令

8.1.1 查询索引

use school;(进入要查询索引的库)
desc  student;(查询整个学生表的索引,key中查看)
show index  from  student\G;(这种查看结果更加详细)

key列显示:
PRI(主键)   UNI(唯一索引)  MUL(辅助索引)

8.1.2 创建索引

1. 单列索引创建:
alter table student  add  index  idx_name(sname);  #给student表中的sname列创建索引叫idx_name
desc  student;  #进行查看

2. 联合索引创建:
alter table student add index idx_sname_sage_ssex(sname,sage,ssex);
#给student表中的sname列,sage,ssex多列创建联合索引
idx_a_b_c----idx_a   idx_a_b    idx_a_b_c

3. 前缀索引创建
alter table student  add index  idex(sname(5));
#给student表中的sname创建前缀索引,取前五个字符

4. 唯一索引创建
alter  table student add  telnum char(11)  not  null;
alter table student  add unique index idx_tel(telnum);

8.1.3 删除索引

alter  table  student drop index  idx;
alter  table student drop  index  idx_name;
alter table student drop index  idx_sname_sage_ssex;

8.2 索引压力测试

8.2.1 压力测试环境准备

  • t100w文档导入数据库

8.2.2 无索引进行并发测试

  • mysqldump --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='LMMN'" engine=innodb --number-of-queries=2000 -uroot -p123 -verbose(此时测试结果显示时间会很长,在1000s左右)

8.2.3 为test库中t100w这个表的测试列k2列创建索引

  • use test;(进入test库)
  • desc t100w;(查看t100w表,此时这个表中没有索引)
  • alter table t100w add index idx_k2(k20;(创建索引)

8.2.4 再次进行测试

  • 依然是上边那条命令,此时会快很多,大概10s左右,这就是索引优化

8.3 索引执行计划管理(desc/explain优化)

8.3.1 执行计划获取(获取优化器选择后的执行计划)

  • desc select * from test.t100w where k2='LMMN';
  • explain select * from test.t100w where k2='LMMN';


    MySQL---DBA---肆(索引及执行计划管理)_第3张图片
    image.png

8.3.2 执行计划重要项分析(上述desc命令结果)

table项(涉及到的表)

指desc的SQL语句涉及到的表(这里指t100w)

type项(指查询类型)

(1)type---ALL:(全表扫描)
含义:
---不走任何索引,所有的表随机扫描,性能最差
可能性:
---查询条件本身查询的列项就没有创建索引
---有索引但不走索引(如下)
1. desc  select *  from  t100w where k2  !=  'asdf';
(不等于的应用不走索引,若查询的是主键列则走的是range)
2. desc select *  from t100w  where k2  like  '%aa%';
(like语句在前面加了%不走索引)
3. desc select *  from t100w where k2  not in ('asda','asas');
(not in子句应用不走索引,若为主键列则走range)
4. desc select *  from t100w;
(目的就是全表扫描,不走索引)


(2)type---index:(全索引扫描)
含义:
---查询的此表中所有列的索引都要进行扫描,要获取的数据适应用于整个索引条件(不太实用)
可能性:
desc select k2 from t100w;


(3)type---range:(索引范围查询)
含义:
应用于索引进行查询项(列)的范围查询
可能性:
1. (>,<,>=,<=,like,between  and...等)
desc select *  from city where id<10;
desc select *  from city where countrycode  like  'CH%';
---上述范围查询能够被B+TREE额外优化到
2. (in(), or)
desc select *  from city where countrycode  in ('CHN','USA');
---这两项一般享受不到B+TREE的额外优化,一般会进行如下优化改写
desc select *  from city where countrycode='CHN'  union all  select *  from  city where countrycode='USA';


(4)type---ref:(辅助索引等值查询)
desc select *  from city where countrycode = 'CHN';


(5)type---eq_ref:(多表连接查询中,非驱动表on的条件列是主键或唯一键的查询)
desc select a.name,b.name  from city  as a  join country  as b  on  a.countrycode=b.code  where a.population<100;


(6)type---const(system):(主键或唯一键的等值查询)
desc select *  from city where id=10;


(7)type---NULL:(获取不到数据)

possible_keys项(可能用到的索引,一个列可能有多个索引)

(1)possible_keys---NULL
---没有和查询体检匹配的索引条目


(2)possible_keys---有值
---有和查询条件匹配的索引条目,但是他走索引。大部分原因是语句查询方式不符合索引应用条目,语句错误

key项(指具体使用到的索引)

指具体使用到的索引,最终所使用的,可以帮助我们判断是否使用了合适的索引

key_len项(按数据类型占最大字节计算,指索引的覆盖长度)

(1)计算方式:字符集
---utf8:一个字符在char与varchar类型中占3个字节
数据类型     not null     null(+1为存储它是空还是非空)
int            4                 4+1=5            #对于int类型,utf8字符集一个字符占4个字节
tinyint        1                 1+1=2            #对于tinyint类型,utf8一个字符占1个字节
char(2)        2*3=6             2*3+1=7          #对于char类型,utf8一个字符占3个字节
varchar(2)     2*3+2=8           2*3+2+1=9        #对于varchar类型,utf8一个字符占3个字节

##注意:varchar类型有两个字节是用来存储字符长度的

---utf8mb4:一个字符在char与varchar类型中占4个字节
数据类型     not null     null(+1为存储它是空还是非空)
int            4                 4+1=5            #对于int类型,utf8mb4字符集一个字符占4个字节
tinyint        1                 1+1=2            #对于tinyint类型,utf8mb4一个字符占1个字节
char(2)        2*4=8             2*4+1=9          #对于char类型,utf8mb4一个字符占4个字节
varchar(2)     2*4+2=10           2*4+2+1=11        #对于varchar类型,utf8mb4一个字符占4个字节


(2)对于单列索引(key_len)
---一般不使用,略


(3)对于联合索引(key_len)
---key_len普遍用于联合索引,主要是优化选择
1. 完美查询过程
含义:
按照索引排序方式进行所有索引的查询(等值查询)
索引:
idx(id,num,k1,k2,k3,k4)
创建:
alter table t1 add index  idx(id,num,k1,k2,k3,k4);
查询:
desc select *  from t1 where id=1 and num=1  and k1='a'   and k2='a'  and  k3='a'   and  k4='a';
结论:
当查询条件中包含了索引列中所有的列条件,并且都是等值查询,name无关排列顺序,都可以走全联合
索引优化;原因是优化器会自动调整顺序,选择最佳的优化效果。所以,我们重点关注的是联合索引建
立的顺序(从左到右),唯一值越多的列越靠左(查询时字符要带引号)

2. 影响key_len查询长度的条件
--按照索引建立顺序在查找条件中,少了任意一个中间列,后续都无法走索引
--在条件查询中,出现了不等值查询,从不等值列开始,所有列都无法走索引(将不等值列放句末)
--若有多子句的条件查询(必须是联合索引)按照子句的执行顺序建立联合索引

Extra项(指出现的额外信息)

using filesort的出现:
原因:
--查询子句中出现group by,order by,distinct等子句的查询条件
优化:
上述子句条件与前方where条件建立联合索引(按顺序)

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

  1. 建立索引时要有主键,如果没有可以找能够作为主键条件的列,创建无关列。
  2. 为经常需要where,order by,group by,join on,distinct等排序操作的条件建立索引,优化查询(若是经常作为条件的列,重复值特别多,可以建立联合索引)
  3. 最好使用唯一值多的列作为索引列(若是索引列重复值较多,可以考虑建立联合索引;如果非使用重复值多的列作为查询条件(比如男女),可以将表逻辑拆分)
  4. 列值长度较长的索引列,建议使用前缀索引
  5. 限制索引数目
    ——每个索引都占用磁盘空间,索引越多,占用磁盘空间越大
    ——修改表时,对索引的重构和更新很麻烦,索引越多,耗时越长
    ——优化器负担会很重,有可能影响优化器选择
  6. 删除不再使用或很少使用的索引(percona toolkit)。表中数据被大量更新,或者数据使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引并将其删除,从而减少索引对更新操作的影响。
  7. 大表加索引,要在业务不繁忙期间操作(pt-osc)
  8. 尽量少在经常更新值的列上建立索引

十. 查询条件不走索引的情况(开发规范)

  1. 没有查询条件,或查询条件中没有建立索引(生产中不建议进行全表扫描)
  2. 查询结果集是原表中大部分数据,应该是25%以上(查询结果太多,优化器感觉没有走索引的必要)
  3. 索引本身失效,统计数据不真实(表中内容变化频繁出现索引失效,删除原索引重建)
  4. 查询条件使用函数在索引列上,或者对索引列进行计算(+,-,*,/,!)
    ——select * from test where id-1=9;(错误案例)
  5. 隐式转换导致索引失效(索引列的数据类型,是字符集还是字符串,在查询时一定要按照数据类型查看)
  6. <,>,not in不走索引(辅助索引)
    ——单独的<,>,in有可能走索引,也有可能不走,与结果集有关。尽量添加limit取少量数据行
    ——or或in尽量改为union all联合子句
  7. like子句"%_"百分号在前也不走索引

你可能感兴趣的:(MySQL---DBA---肆(索引及执行计划管理))