索引是一种用于快速查询和检索数据的数据结构,其本质可以看成是一种排序好的数据结构。索引的作用就相当于书的目录。打个比方: 我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。索引底层数据结构存在很多种类型,常见的索引结构有: B 树, B+树 和 Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyIsam,都使用了 B+树作为索引结构。
索引的存储原理大致可以概括为一句话:以空间换时间。
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往是存储在磁盘上的文件中的(可能存储在单独的索引文件中,也可能和数据一起存储在数据文件中)。
数据库在未添加索引进行查询的时候默认是进行全文搜索,也就是说有多少数据就进行多少次查询,然后找到相应的数据就把它们放到结果集中,直到全文扫描完毕。
1.优点:
大大提高数据查询速度。
可以提高数据检索的效率,降低数据库的IO成本,类似于书的目录。
通过索引列对数据进行排序,降低数据的排序成本降低了CPU的消耗。
被索引的列会自动进行排序,包括【单例索引】和【组合索引】,只是组合索引的排序需要复杂一些。
如果按照索引列的顺序进行排序,对order by语句来说,效率就会提高很多。
2.缺点:
索引会占据磁盘空间。
索引虽然会提高查询效率,但是会降低更新表的效率。比如每次对表进行增删改查操作,MySQL不仅要保存数据,还有保存或者更新对应的索引文件。
维护索引需要消耗数据库资源。
注意:但是,使用索引一定能提高查询性能吗? 大多数情况下,索引查询都是比全表扫描要快的。但是如果数据库的数据量不大,
那么使用索引也不一定能够带来很大提升。
(1)我们可以按照四个角度来分类索引。
按「数据结构」分类:B+tree索引、Hash索引、Full-text索引。
按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)。
按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引。
按「字段个数」分类:单列索引、联合索引。
InnoDB 是在 MySQL 5.5 之后成为默认的 MySQL 存储引擎,B+Tree 索引类型也是 MySQL 存储引擎采用最多的索引类型。
在创建表时,InnoDB 存储引擎会根据不同的场景选择不同的列作为索引:
如果有主键,默认会使用主键作为聚簇索引的索引键(key);
如果没有主键,就选择第一个不包含 NULL 值的唯一列作为聚簇索引的索引键(key);
在上面两个都没有的情况下,InnoDB 将自动生成一个隐式自增 id 列作为聚簇索引的索引键(key);
其它索引都属于辅助索引(Secondary Index),也被称为二级索引或非聚簇索引。创建的主键索引和二级索引默认使用的是 B+Tree 索引。
从物理存储的角度来看,索引分为聚簇索引(主键索引)、二级索引(辅助索引)。
区别:
主键索引的 B+Tree 的叶子节点存放的是实际数据,所有完整的用户记录都存放在主键索引的 B+Tree 的叶子节点里;
二级索引的 B+Tree 的叶子节点存放的是主键值,而不是实际数据。
所以,在查询时使用了二级索引,如果查询的数据能在二级索引里查询的到,那么就不需要回表,这个过程就是覆盖索引。
如果查询的数据不在二级索引里,就会先检索二级索引,找到对应的叶子节点,获取到主键值后,然后再检索主键索引,
就能查询到数据了,这个过程就是回表。
(2)常见索引的介绍
1.主键索引:primary key
设定为主键后,数据库自动建立索引,InnoDB为聚簇索引,主键索引列值不能为空(Null)。
2.唯一索引:
索引列的值必须唯一,但允许有空值(Null),但只允许有一个空值(Null)。
3.复合索引:
一个索引可以包含多个列,多个列共同构成一个复合索引。
4.全文索引:
Full Text(MySQL5.7之前,只有MYISAM存储引擎引擎支持全文索引)。
全文索引类型为FULLTEXT,在定义索引的列上支持值的全文查找允许在这些索引列中插入重复值和空值。全文索引可以在Char、VarChar 上创建。
5.空间索引:
MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型,MySQL在空间索引这方年遵循OpenGIS几何数据模型规则。
6.前缀索引:
在文本类型为char、varchar、text类列上创建索引时,可以指定索引列的长度,但是数值类型不能指定。
通过explain关键字查看这条语句的执行计划
key:实际使用的索引,如果为NULL,则表示没有使用索引
type:显示查询使用了何种类型,从好到坏,依次为:
system:表中只有一行数据
const:单表中最多只有一条匹配行,比如说根据主键或者说唯一索引进行查询
eq-ref:使用唯一索引,比如说在联表查询中使用主键或者唯一索引作为关联条件
ref:使用非唯一索引或者唯一索引前缀扫描
range:索引范围扫描
index:全索引扫描
all:全表扫描
possible_key:能使用那个索引在表中找到该行
rows:大致估算出找到所需的记录所需要读取的行数
索引失效以及为什么失效
当我们使用左或者左右模糊匹配的时候,也就是 like %xx 或者 like %xx%这两种方式都会造成索引失效;因为索引是通过前缀进行构建的。
当我们在查询条件中对索引列使用函数,就会导致索引失效。因为MySQL没有对使用了函数后的索引列创建索引。
当我们在查询条件中对索引列进行表达式计算,也是无法走索引的。同上。
MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。如果字符串是索引列,而条件语句中的输入参数是数字的话,
那么索引列会发生隐式类型转换,由于隐式类型转换是通过 CAST 函数实现的,等同于对索引列使用了函数,所以就会导致索引失效。
联合索引要能正确使用需要遵循最左匹配原则,也就是按照最左优先的方式进行索引的匹配,否则就会导致索引失效。
在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。
索引为什么能提高查询性能
MySQL 的数据是持久化的,意味着数据(索引+记录)是保存到磁盘上的,因为这样即使设备断电了,数据也不会丢失。
数据存储在磁盘( SSD 跟 CPU 性能也不在一个量级),而磁盘处理数据很慢;提高磁盘性能主要通过减少 I/O 次数,以及单次 I/O 有效数据量;
索引通过多阶(一个节点保存多个数据,指向多个子节点)使树的结构更矮胖,从而减少 I/O 次数;
索引通过 B+ 树,把业务数据与索引数据分离,来提高单次 I/O 有效数据量,从而减少 I/O 次数;
索引通过树数据的有序和「二分查找」(多阶树可以假设为多分查找),大大缩小查询范围;
索引针对的是单个字段或部分字段,数据量本身比一条记录的数据量要少的多,这样即使通过扫描的方式查询索引也比扫描数据库表本身快的多;
索引的数据结构
MySQL 默认的存储引擎 InnoDB 采用的是 B+ 作为索引的数据结构,原因有:
B+ 树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的 B 树,B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。
B+ 树有大量的冗余节点(所有非叶子节点都是冗余索引),这些冗余索引让 B+ 树在插入、删除的效率都更高,比如删除根节点的时候,不会像 B 树那样会发生复杂的树的变化;
B+ 树叶子节点之间用链表连接了起来,有利于范围查询,而 B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。