上一篇详细分析了mysql innerDB引擎索引得数据结构,本章我们来了解一下mysql的索引分类以及使用的情况及注意事项
根据划分不同,可能平常经常听到各种各样的索引名称,每次搜索索引类型可能看到的都不一样(概念容易混淆),下面详细分析一下:
索引分类:
这个是网上找到的一篇比较完整的索引划分,可以参考一下
(从数据结构角度划分)
Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE
FULLTEXT
全文索引,MySQL里面很早就支持了,只不过一直以来只支持英文,且只能用于数据库引擎为MYISAM的数据表。缘由是他从来都使用空格来作为分词的分隔符,而对于中文来讲,显然用空格就不合适,需要针对中文语义进行分词。但从MySQL 5.7开始,MySQL内置了ngram全文检索插件,用来支持中文分词,并且对MyISAM和InnoDB引擎有效。
HASH
HASH值几乎100%唯一,所以索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合HASH索引无效。
BTREE
树形结构索引,每次查询都是从树的入口开始,异常遍历节点,获取值,这是MySQL里默认和最常用的索引类型
RTREE
RTREE在MySQL很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。相对于BTREE,RTREE的优势在于范围查找
(从物理存储角度划分)
聚集索引(聚簇索引)
主键作为聚集索引(如果没有主键,先选择唯一索引,如果还没有,使用默认 rowId),而非聚集索引可以有多个,除了聚集索引其他都是非聚集索引(比如下面提到的二级索引)
聚簇索引会存放所有表记录
非聚集索引
存放对应索引字段和主键(查询会有两次io,需要回表)
关于聚集索引与非聚集索引的详细问题:
不同的存储引擎对聚集索引和非聚集索引的实现方式是不同的:
对于InnerDB来说,使用聚集索引的主键索引行数据和主键B+树存储在一起,使用非聚集索引的辅助键B+树只存储辅助键和主键,主键和非主键B+树几乎是两种类型的树。辅助键索引也称为非主键索引或二级索引或次级索引.
文件区分:
innerDB的文件:
.frm:表的定义,就是描述表结构的文件
.ibd:表的数据文件和索引文件 i表示的是InnoDB和Index d表示的是Data
MyISAM的文件:
.frm:表的定义,就是描述表结构的文件
.MYD:数据存储文件 D表示的是Data MY表示的是MyISAM
.MYI:索引存储文件 I表示的是Index
innerDB存放索引方式是 将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id = 14"这样的条件查找主键(使用主键索引),则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。若对Name列进行条件搜索(使用二级索引),则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作(回表),最终到达叶子节点即可获取整行数据。
如图:
上图为主键索引树
这是二级索引树
疑问?
1. 为什么innerDB要用两颗树来维护索引?如果用一个,不是就不需要回表操作了?
a . 冗余的存储数据,如果每个二级索引都存储其他列数据,那么数据就特别大
b. 还有一点就是同一份数据存在两个索引上,一旦对数据库的数据进行修改,还需要保证两颗索引树的数据一致性
2. 为什么InnoDB表必须有主键,并且推荐使用整型的自增主键?不用UUID
GEN_CLUST_INDEX来做主键),使用整型自增的主键是为了方便检索,整型肯定比字符串快速
3.主键索引就是聚集索引?
MySQL默认是InnoDB引擎,所以创建的主键也就默认是聚集索引,在MyISAM中就不是聚集索引了
对于MyISAM来说,它不支持聚集索引,所以主键索引和辅助键索引都是非聚集索引。主键B+树和辅助键B+树在叶子节点存储指向真正数据行的指针,通过主键索引树或者辅助键索引树都可以直接找到相应数据行的全部数据。
总结:聚集索引查询数据速度快,插入数据速度慢;非聚集索引反之(这就是平常面试经常说的索引插入数据速度慢的原因)
关于聚集索引与非聚集索引可能也没有说得太详细,这篇文章写的很好,推荐看一看,我也有很多借鉴了其中的内容
(从逻辑角度划分)
删除索引语法补充:DROP INDEX 索引名称 on 表名;
查看索引语法补充:SHOW INDEX FROM 表名;
单列索引:
即一个索引只包含单个列,一个表可以有多个单列索引
语法:
CREATE INDEX 索引名称 ON 表名(字段名);
唯一索引:
和单列索引类似,只是索引列的值必须唯一,但允许有空值
语法:
CREATE UNIQUE INDEX 索引名称 ON 表名(字段名);
主键索引:
设定为主键后,数据库会自动建立索引
ps:不需要手动建立,要设定其实就是设定主键 PRIMARY KEY
组合索引(复合索引,多列索引。。。好几种叫法,都是一个):
即一个索引包含多个列,复合索引比单值索引所需要的开销更小,相对来说用得更多,但要注意索引的最左前缀原则(后面索引使用时详细分析)
语法:
CREATE INDEX 索引名称 ON 表名(列1,列2,....);
创建唯一组合索引
CREATE UNIQUE INDEX 索引名称 ON 表名(列1,列2,....);
全文索引:
对文本的内容进行分词,进行搜索
使用:
在使用中文检索分词插件ngram之前,先得在MySQL配置文件里面设置他的分词大小(默认是2) ngram_token_size=2
语法:
CREATE FULLTEXT INDEX 索引名称 ON 表名(字段1,字段2(索引的长度)) with parser ngram; ps:长度可以不填只填字段,字段可以多个也可以一个
索引使用原则
1. 除了聚簇索引,其他的索引并不是表创建的时候就需要创建,根据业务情况而定
2. 对于经常被查询的列、经常用于表连接的列、经常排序分组的列,需要创建索引
3. 如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列,跳过了后面的就用不了索引
4. 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
5. 尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少 select * 语句
6. mysql在使用不等于(!=或者<>),not in ,not exists 的时候无法使用索引会导致全表扫描 < 小于、 > 大于、 <=、>= 这些,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引
7. like 不要以%开头,不然全表扫描
8. 字符串不加单引号索引失效
9. 少用or或in,用它查询时,mysql不一定使用索引,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引
10. 不建议在频繁更新的字段上建立索引
11. 如果要进行join查询,那么被join的字段必须类型相同并建立索引,因为join字段类型不一致会导致全表扫描。
。。。。。。。
一些索引的使用情况:
索引的使用需要注意的地方有很多,牢记索引数据结构,知道原理才能优化得更好,业务情况也是决定索引得重大因素
补充
最后补充几个相关面试题:
1. 什么叫密集索引,什么叫稀疏索引?
所谓密集和稀疏,指的是索引数是否保护除索引外的数据。所以密集索引就是聚簇索引,稀疏索引就是非聚集索引(二级索引) myisam引擎下都是稀疏索引
2. innerDB的三大特性?
自适应哈希索引:mysql自动维护,和hashMap一样的,只是没有红黑树
双写缓冲区
buffer-pool
3. 什么叫覆盖索引?
覆盖索引不是索引。只是一种优化方式,就是多列索引尽量查询覆盖到更多的字段,让扫描范围更加的小
一个想过得更好的码农---邋遢道人