1、什么是索引
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。索引是数据库中用来提高性能的最常用的工具。
我们通常所说的索引,包括聚集索引、覆盖索引、组合索引、前缀索引、唯一索引等,没有特别说明,默认都是使用B+树结构组织(多路搜索树,并不一定是二叉的)的索引。
优势与劣势
优势:
1、提高数据检索的效率,降低数据库的IO成本。
2、通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
劣势:
1、实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的。
2、虽然索引大大提高了查询效率,同时却也降低更新表的速度
2 、索引结构(重要)
索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。
MySQL目前提供了以下4种索引:
BTREE 索引 : 最常见的索引类型,大部分索引都支持 B 树索引。
HASH 索引:只有Memory引擎支持 , 使用场景简单 。
R-tree 索引(空间索引):空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少,不做特别介绍。
Full-text (全文索引) :全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。
MyISAM、InnoDB、Memory三种存储引擎对各种索引类型的支持
索引 | InnoDB引擎 | MyISAM引擎 | Memory引擎 |
BTREE索引 | 支持 | 支持 | 支持 |
HASH 索引 | 不支持 | 不支持 | 支持 |
R-tree 索引 | 不支持 | 支持 | 不支持 |
Full-text | 5.6版本之后支持 | 支持 | 支持 |
我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用 B+tree 索引,统称为 索引。
BTree 与 B+Tree
BTree又叫多路平衡搜索树,一颗m叉的BTree特性如下:
树中每个节点最多包含m个孩子。
除根节点与叶子节点外,每个节点至少有[ceil(m/2)]个孩子。ceil为向上取整
若根节点不是叶子节点,则至少有两个孩子。
所有的叶子节点都在同一层。
每个非叶子节点由n个key与n+1个指针组成,其中[ceil(m/2)-1]
MySQL 数据库使用最多的索引类型是BTREE索引,底层基于B+树数据结构来实现。
B+ 树是基于B 树和叶子节点顺序访问指针进行实现,它具有B树的平衡性,并且通过顺序访问指针来提高区间查询的性能。
进行查找操作时,首先在根节点进行二分查找,找到key所在的指针,然后递归地在指针所指向的节点进行查找。直到查找到叶子节点,然后在叶子节点上进行二分查找,找出 key 所对应的数据项。
为什么索引要用B+树来实现呢,而不是用二叉树?
B+树有个特点,就是够矮够胖,能有效地减少访问节点次数从而提高性能。
虽然二叉树也有很好的查找性能log2N,但是当N比较大的时候,树的深度比较高。数据查询的时间主要依赖于磁盘IO的次数,二叉树深度越大,查找的次数越多,性能越差。最坏的情况会退化成链表。所以,B+树更适合作为MySQL索引结构。
那又为什么不用B树呢?
因为B树的分支结点存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫。
而由于B+树的数据都存储在叶子结点中,叶子结点均为索引,方便扫库,只需要扫一遍叶子结点即可。所以B+树更加适合在区间查询的情况,而在数据库中基于范围的查询是非常频繁的,所以B+树更适合用于数据库索引。
3、 索引分类与设计原则
索引分类
主键索引:索引列中的值必须是唯一的,不允许有空值。
唯一索引 :索引列的值必须唯一,但允许有空值。
普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值。
全文索引:只能在文本类型CHAR,VARCHAR,TEXT类型字段上创建全文索引。字段长度比较大时,如果创建普通索引,在进行like模糊查询时效率比较低,这时可以创建全文索引。MyISAM和InnoDB中都可以使用全文索引。
空间索引:MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型。MySQL在空间索引这方面遵循OpenGIS几何数据模型规则。
复合索引 :即一个索引包含多个列。组合索引的使用,需要遵循最左前缀匹配原则(最左匹配原则)。一般情况下在条件允许的情况下使用组合索引替代多个单列索引使用。
聚集索引与非聚集索引
聚集索引严格来说并不是索引类型,而是一种数据存储方式,具体细节依赖于其实现方式。如innodb聚集索引的叶子节点存放了整张表的行记录(B+Tree)。
聚集索引类似字典的拼音目录。表中的数据按照聚集索引的规则来存储的。就像新华字典,整本字典是按照A-Z的顺序来排列。这也是一个表只能有一个聚集索引的原因。
聚簇索引相比非聚簇索引有什么优点?
数据访问更快,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快。
聚集索引叶子节点的存储是逻辑上连续的,所以对于主键的排序查找和范围查找速度会更快。
索引设计原则
- 对查询频次较高,且数据量比较大的表建立索引。
- 索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。
- 对于插入、更新、删除等DML操作比较频繁的表来说不要使用索引。
- 索引数量不是多多益善,索引越多,维护索引的代价自然也就水涨船高。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护代价,降低DML操作的效率,增加相应操作的时间消耗。另外索引过多的话,MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价。
- 使用短索引。在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率。
- 利用最左前缀(最左索引),N个列组合而成的组合索引,那么相当于是创建了N个索引,如果查询时where子句中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率。
最左前缀索引
创建复合索引:
CREATE INDEX idx_name_email_status ON tb_seller(a,b,c);
就相当于
对a创建索引 ;
对a, b创建了索引 ;
对a, b, c创建了索引 ;
只要查询条件包含了name,就会利用索引查询
b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+数是按照从左到右的顺序来建立搜索树的。
比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;
但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。
比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。
4、索引优化
避免索引实效情况
- 全值匹配 ,对索引中所有列都指定具体值。
- 最左前缀法则,如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。
- 不要在索引列上进行运算操作, 索引将失效。
- 字符串不加单引号,造成索引失效。
- 尽量使用覆盖索引,避免select * ,如果查询列,超出索引列,也会降低性能。
- 用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
- 以 %开头的Like模糊查询,索引失效。解决方案 :通过覆盖索引来解决,这样即使是模糊查询也会走索引。
- 如果MySQL评估使用索引比全表更慢,则不使用索引。
- is NULL , is NOT NULL 有时 索引失效。比如:一个字段都不为空,那么使用NOT NULL还不如走全表扫描,mysql会自动判断。
- in 走索引, not in 索引失效。
- 单列索引和复合索引。尽量使用复合索引,而少使用单列索引 。针对单列索引,数据库会选择一个最优的索引(辨识度最高索引)来使用,并不会使用全部索引 。