vlambda博客
学习文章列表

MySQL索引有哪些分类,你真的清楚吗?

干货福利,不错过


  索引最形象的比喻就是图书的目录,注意只有在大量数据中查询时索引才显得有意义。



索引是什么


MySQL官方定义:索引(Index)是帮助 MySQL 高效获取数据的数据结构。

在MySQL中索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。常见的索引归类如下:

按数据结构分类:B+tree索引、Hash索引、Full-text索引。

按物理存储分类:聚集索引、非聚集索引(也叫二级索引、辅助索引)。

按字段特性分类:主键索引(PRIMARY KEY)、唯一索引(UNIQUE)、普通索引(INDEX)、全文索引(FULLTEXT)。

按字段个数分类:单列索引、联合索引(也叫复合索引、组合索引)。



按数据结构分类


MySQL索引按数据结构分类可分为:B+tree索引、Hash索引、Full-text索引。

注:InnoDB 实际上也支持 Hash 索引,但是 InnoDB 中 Hash 索引属于是自适应 Hash 索引,它的创建过程由存储引擎引擎自动优化创建,不能人为干预是否为表创建 Hash 索引。

B+tree 索引

B+tree 索引是 MySQL 中被存储引擎采用最多的索引类型。它适用于全键值、键值范围和最左前缀查找。使用联合索引时,如果不是按照索引列的顺序进行查找,则无法使用索引。除了适用于查找,还可以用于排序和分组。

在 MySQL 中为什么会选用 B+tree 做索引结构呢?

B+tree 是在 B树 基础上的一种优化,其更适合做存储索引结构。在 B+tree 中,非叶子节点上仅存储键值,不存储数据;而所有数据记录均存储在叶子节点上,并且数据是按照顺序排列的。此外在 B+tree 中各个数据页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。B+tree 的结构图如下:

MySQL索引有哪些分类,你真的清楚吗?

(图片来源于网络)

B+tree 结构实现数据索引具有如下优点:

  1. 非叶子节点上可以存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树也就会变得更矮更胖。

    这样一来我们查找数据进行磁盘I/O的次数就会大大减少,数据查询的效率也会更快。

  2. 所有数据记录都有序存储在叶子节点上,就会使得范围查找,排序查找,分组查找以及去重查找变得异常简单。

  3. 数据页之间、数据记录之间都是通过链表链接的,有了这个结构的支持就可以方便地在数据查询后进行升序或者降序操作。

Hash 索引

Memory 引擎默认支持哈希索引,如果多个 Hash 值相同,出现哈希碰撞,那么索引就以链表方式存储。(这有点类似于 Java 中的 HashMap,哈哈~)InnoDB 或 MyISAM 存储引擎页支持 Hash 索引,但是需要通过伪 Hash 索引来实现,叫自适应 Hash 索引。

MySQL索引有哪些分类,你真的清楚吗?

(图片来源于网络)

  1. Hash 索引仅仅能满足等值查询,不能进行范围查询由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和 Hash 运算前完全一样。

  2. Hash 索引无法通过操作索引来排序由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且 Hash 值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算。

  3. 组合 Hash 索引不能利用部分索引键进行查询对于组合 Hash 索引,索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。

  4. Hash 索引依然需要回表扫描Hash 索引是将索引键通过 Hash 运算之后,将 Hash 运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键可能存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。

  5. Hash 索引遇到大量 Hash 值相等的情况后性能并不一定就会比 B+Tree 索引高区分度低的索引键(如,性别),如果创建 Hash 索引,那么将会存在大量记录指针信息与同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。

Full-text 索引

Full-text 索引一般使用倒排索引实现。倒排索引同 B+tree 索引一样,也是一种索引结构。

MySQL 中 InnoDB 存储引擎在之前版本中是不支持全文检索的,要使用全文检索的话只能使用 MySIAM 存储引擎。在 MySQL 5.6.4 版本中 InnoDB 存储引擎才开始支持 Full-text 索引。

对于文本类型的大对象,或者较大的 CHAR 类型的数据,如果使用普通索引,那么匹配文本前几个字符还是可行的,但是想要匹配文本中间的几个单词,那么就要使用 LIKE %word% 来匹配,这样需要很长的时间来处理,响应时间会大大增加,这种情况,就可使用 FULLTEXT 索引了,在生成 FULLTEXT 索引时,会为文本生成一份单词的清单,在索引时及根据这个单词的清单来索引。

Full-text 索引的查询有自己特殊的语法,而不能使用 LIKE 模糊查询的语法,语法如下:

SELECT * FROM table_name MATCH(ft_index) AGAINST('查询字符串');



按物理存储分类


MySQL 索引按叶子节点存储的是否为完整表数据分为:聚集索引、非聚集索引(也叫二级索引、辅助索引)。

聚簇索引

聚簇索引就是按照每张表的主键构造一颗 B+tree,同时叶子节点中存放的就是整张表的行记录数据,聚集索引的叶子节点被称为数据页。

(图片来源于网络)

InnoDB 表要求必须有聚簇索引,默认在主键字段上建立聚簇索引,在没有主键字段的情况下,表的第一个非空的唯一索引将被建立为聚簇索引,在前两者都没有的情况下,InnoDB 将自动生成一个隐式的自增id列,并在此列上建立聚簇索引。

非聚集索引(也叫二级索引、辅助索引)

非聚集索引的结构和聚集索引基本相同(非叶子节点存储的都是索引指针),区别在于叶子节点存放的不是行数据而是数据主键。因此在使用非聚集索引进行查找时,需要先查找到主键值,然后再到聚集索引中进行查找。

(图片来源于网络)

两种索引的区别:每个索引上包含的字段内容不同,聚集索引包含所有真实的物理数据,非聚集索引只包含索引字段和主键字段。此外,聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个。

那非聚集索引这种查询方式算不算回表呢?

回表查询简单来说就是通过非聚集索引查询数据时,得不到完整的数据内容,需要再次查询主键索引来获得数据内容。

所以如果使用非聚集索引后还需要使用其他字段的(包括在 where 条件中或者 select 子句中),则需要通过主键索引回表到聚集索引获取其他字段。如果是非聚集索引可以满足 SQL 语句的所有字段的,则被称为全覆盖索引,没有回表开销。

避免回表查询问题,常见的方式就是建立联合索引(组合索引),实现索引覆盖,从而避免回表查询。索引覆盖就是指索引的叶子节点已经包含了查询的数据,满足查询要求,没必要再回表进行查询。



按字段特性分类


MySQL索引按字段特性分类可分为:主键索引(PRIMARY KEY)、唯一索引(UNIQUE)、普通索引(INDEX)、全文索引(FULLTEXT)。

主键索引(PRIMARY KEY)

建立在主键上的索引被称为主键索引,一张数据表只能有一个主键索引,索引列值不允许有空值,通常在创建表时一起创建。

唯一索引(UNIQUE)

建立在 UNIQUE 字段上的索引被称为唯一索引,一张表可以有多个唯一索引,索引列值允许为空,列值中出现多个空值不会发生重复冲突。

普通索引(INDEX)

建立在普通字段上的索引被称为普通索引。

全文索引(FULLTEXT)

MyISAM 存储引擎支持 Full-text 索引,用于查找文本中的关键词,而不是直接比较是否相等。Full-text 索引一般使用倒排索引实现,它记录着关键词到其所在文档的映射。

InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持 Full-text 索引。



按索引字段个数分类


MySQL 索引按字段个数分类可分为:单列索引、联合索引(也叫复合索引、组合索引)。

单列索引

建立在单个列上的索引被称为单列索引。

联合索引(复合索引、组合索引)

建立在多个列上的索引被称为联合索引,又叫复合索引、组合索引。在 MySQL 中使用联合索引时要遵循最左前缀匹配原则。所以我们需要注意如下几个方面:

  1. 实际业务场景中创建联合索引时,我们应该把识别度比较高的字段放在前面,提高索引的命中率,充分的利用索引。

  2. 创建联合索引后,该索引的任何最左前缀都可以用于查询。比如当你有一个联合索引(col1, col2, col3),该索引的所有最左前缀为(col1)、(col1, col2)、(col1, col2, col3),包含这些列的所有查询都会使用该索引进行查询。

  3. 虽然联合索引可以避免回表查询,提高查询速度,但同时也会降低表数据更新的速度。因为联合索引列更新时,MySQL 不仅要保存数据,还要维护一下索引文件。所以不要盲目使用,应根据业务需求来创建。


END


请戳 “阅读原文”,一起来充电!