什么是索引?
索引是提高数据库性能的重要方式,用来快速找出数据表中的特定记录。如果在表中查询的列有一个索引,MySQL 能快速到达一个位置去搜寻数据,而不必查看所有数据。一个表可以创建多个索引,一个索引可以包含一个或者多个字段。
简单解释:索引类似于书的目录,在没有目录的情况下,要从书中查找某项内容就必须阅读全文,而有了目录之后,通过页码就可以很快定位到相关内容。
使用索引可以很大程度上提高数据库的查询速度,还有效的提高了数据库系统的性能。
在 MySQL 中,通常有以下两种方式访问数据库表的行数据:
顺序访问
顺序访问是在表中实行全表扫描,从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据。顺序访问实现比较简单,但是当表中有大量数据的时候,效率非常低下。例如,在几千万条数据中查找少量的数据时,使用顺序访问方式将会遍历所有的数据,花费大量的时间,显然会影响数据库的处理性能。
索引访问
索引访问是通过遍历索引来直接访问表中记录行的方式。使用这种方式的前提是对表建立一个索引,在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快捷地查找到数据。索引存储了指定列数据值的指针,根据指定的排序顺序对这些指针排序。扫描索引的速度一般远远大于扫描实际数据行的速度,所以采用索引的方式可以大大提高数据库的工作效率。
简而言之,不使用索引,MySQL 就必须从第一条记录开始读完整个表,直到找出相关的行。表越大,查询数据所花费的时间就越多。如果表中查询的列有一个索引,MySQL 就能快速到达一个位置去搜索数据文件,而不必查看所有数据,这样将会节省很大一部分时间。
索引的优点:
- 通过创建唯一索引可以保证数据库表中每一行数据的唯一性。
- 可以大大加快数据的查询速度,这是使用索引最主要的原因。
- 可以减少分组和排序查询的时间。
索引的缺点:
- 创建和维护索引组要耗费时间,并且随着数据量的增加所耗费的时间也会增加。
- 索引需要占磁盘空间。
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态维护。
注意:
索引可以提高查询速度,但是会影响插入记录的速度。因为,向有索引的表中插入数据时,数据库系统会首先按照索引进行排序,这样就降低了插入数据的速度,插入大量记录时的速度影响会更加明显。这种情况下,最好的办法是先删除表中的索引,然后插入数据,插入完成后,再创建索引。
索引的分类
通常情况下将索引分类为:主键索引、唯一索引、全文索引、普通索引和组合索引。
另外 按照物理存储的角度可以分为:聚簇索引和非聚簇索引(二级索引/辅助索引)。
聚簇索引:主键索引,其实就是聚簇索引(Clustered Index)
非聚簇索引:主键索引之外,其他的都称之为非主键索引,也被称为二级索引(Secondary Index),或者叫作辅助索引。
所以,当我们需要查询的时候:
- 如果是通过主键索引来查询数据,例如 select * from user where id=100,那么此时只需要搜索主键索引的 B+Tree 就可以找到数据。
- 如果是通过非主键索引来查询数据,例如 select * from user where username=’javaboy’,那么此时需要先搜索 username 这一列索引的 B+Tree,搜索完成后得到主键的值,然后再去搜索主键索引的 B+Tree,就可以获取到一行完整的数据。
对于第二种查询方式而言,一共搜索了两棵 B+Tree,第一次搜索 B+Tree 拿到主键值后再去搜索主键索引的 B+Tree,这个过程就是所谓的回表。
从上面的分析中我们也能看出,通过非主键索引查询要扫描两棵 B+Tree,而通过主键索引查询只需要扫描一棵 B+Tree,所以如果条件允许,还是建议在查询中优先选择通过主键索引进行搜索。
主键索引
主键索引是一种特殊的唯一索引,不允许值重复或者值为空。非空唯一索引,一个表只能有一个主键索引。
创建主键索引通常使用 PRIMARY KEY 关键字。
唯一索引
唯一索引可以避免数据出现重复。
唯一索引列的值必须唯一,允许有空值。如果是组合索引,则列值的组合必须唯一。不可以出现相同的值,可以有null值。
创建唯一索引通常使用 UNIQUE 关键字。
普通索引
普通索引是 MySQL 中最基本的索引类型,它没有任何限制,唯一任务就是加快系统对数据的访问速度。
普通索引允许在定义索引的列中插入重复值和空值。允许出现相同的索引内容。
创建普通索引时,通常使用的关键字是 INDEX 或 KEY。
全文索引
全文索引主要用来查找文本中的关键字,只能在 CHAR、VARCHAR 或 TEXT 类型的列上创建。在 MySQL 中只有 MyISAM 存储引擎支持全文索引。
全文索引允许在索引列中插入重复值和空值。基于倒排索引。
不过对于大容量的数据表,生成全文索引非常消耗时间和硬盘空间。
创建全文索引使用 FULLTEXT 关键字。
组合索引
组合索引是将原表的多个列共同组成一个索引。多列索引是在表的多个字段上创建一个索引。该索引指向创建时对应的多个字段,可以通过这几个字段进行查询。但是,只有查询条件中使用了这些字段中第一个字段时,索引才会被使用。
注意📢:一个表可以有多个单列索引,但这些索引不是组合索引。一个组合索引实质上为表的查询提供了多个索引,以此来加快查询速度。比如,在一个表中创建了一个组合索引(c1,c2,c3),在实际查询中,系统用来实际加速的索引有三个:单个索引(c1)、双列索引(c1,c2)和多列索引(c1,c2,c3)。没有(c1,c3)的原因是索引插叙要满足最左前缀法则,意思就是从左到右,不能跳索引,否则索引就会失效。
索引的存储方式
哈希表
Hash表不适合做范围查询,Hash表更适合做等值查询,另外Hash表还存在Hash函数选择和Hash值冲突等问题。
B+树
几种常见的二叉树
- BST(搜索二叉树):有序,但是无法保持平衡,可能形成链表,导致树深度过深。
- AVL(平衡二叉树):有序,左右子树高度差不能超过1,通过旋转解决了平衡的问题,但是旋转操作效率太低。
- RBT(红黑树):有序,是一种弱平衡树,AVL树的一个变种,最长子树不超过最短子树的两倍,通过损失部分部分查询性能来获得插入性能的提升。
- B-Tree:B树(不是B减树),是通过将二叉树改为多路平衡搜索树,解决了树过高的问题。
- B+Tree:B+树,在 B 树的基础上,将非叶节点改造为不存储数据的纯索引节点,进一步降低了树的高度;此外将叶节点使用指针连接成链表,范围查询更加高效。B+树叶节点之间只是逻辑相邻,而不是物理相邻,甚至在物理位置相邻很远的情况下,依然会产生很多的随机IO。B+树减少随机IO的关键在于,利用叶节点逻辑相邻的特性,尽可能地做到物理相邻(数据被分配到连续的页中),使得在读取叶节点中的大量记录时可以使用顺序IO。这点很重要!
什么是B树?和B+树有什么区别?
B+tree只在叶子节点存储数据,而 B-tree非叶子节点也存储数据。

MySQL索引的其他概念
回表
覆盖索引
就是把单列的非主键 索引 修改为 多字段 的联合索引, 在一棵索引数上。 就找到了想要的数据, 不需要去主键索引树上,再检索一遍 这个现象,称之为 索引覆盖。
覆盖索引(covering index ,或称为索引覆盖)即从非主键索引中就能查到的记录,而不需要查询主键索引中的记录,避免了回表的产生减少了树的搜索次数,显著提升性能。
覆盖索引避免了回表现象的产生,从而减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是性能优化的一种手段。
最左匹配
索引下推
前缀索引
前缀索引是指对字符类型字段的前几个字符或对二进制类型字段的前几个bytes建立的索引,而不是在整个字段上建索引。
常见的关于MySQL索引的面试题
1. 索引是不是越多越好?
索引可以大大提高查询的效率,但是索引并不是越多越好,索引需要占用磁盘空间,当对表中的数据进行增、删和改的时候,索引也要动态维护,创建和维护索引需要耗费时间。
2. 为什么索引不使用B树,而是用B+树存储?
3. 什么情况下索引会失效?
索引可以提高查询的速度,但并不是使用带有索引的字段查询时,索引都会起作用。使用索引有几种特殊情况,在这些情况下,有可能使用带有索引的字段查询时,索引并没有起作用。
- 使用like模糊查询,当’%三’在前面就会导致索引失效,’三%’在后面则仍会使用索引查询。
- 创建了组合索引,但是查询条件中没有使用组合索引的第一个列,导致索引失效,查询条件需要按照组合索引列的顺序才能才能触发索引。
- 查询条件中使用了OR关键字,如果前后字段都是索引列会使用索引,如果有个一个不是则索引失效。
- todo
参考文章
文章参考:
文章参考:
参考:
参考:
