MySQL的索引分类
在前面我为什么用多样化去形容数据库索引呢?因为确实如此,先列一些大家都听说过的索引称呼:聚簇索引、非聚簇索引、唯一索引、主键索引、联合索引、全文索引、单列索引、多列索引、复合索引、普通索引、二级索引、辅助索引、次级索引、有序索引、B+Tree
索引、R-Tree
索引、T-Tree
索引、Hash
索引、空间索引、前缀索引......
是不是看的眼花缭乱,这些都是
MySQL
中索引的一些称呼,一通看下来,估计大家看“索引”两个字都有点不认识了^_^
但实际上MySQL
中真的有这么多索引类型吗?其实并没有,上述列出的索引称呼中,有几个称呼对应的索引是同一个,有一部分只是逻辑上的索引,那索引究竟该如何分类呢?其实从不同的层面上来说,可以将索引划分为不同的类型,接下来重点聊一聊。
1.1、数据结构层次
前面聊索引本质的时候提到过,索引建立后也会在磁盘生成索引文件,那每个具体的索引节点该如何在本地文件中存放呢?这点是由索引的数据结构来决定的。比如索引的底层结构是数组,那所有的索引节点都会以Node1→Node2→Node3→Node4....
这样的形式,存储在磁盘同一块物理空间中,不过MySQL
的索引不支持数组结构,或者说数组结构不适合作为索引结构,MySQL
索引支持的数据结构如下:
B+Tree
类型:MySQL
中最常用的索引结构,大部分引擎支持,有序。Hash
类型:大部分存储引擎都支持,字段值不重复的情况下查询最快,无序。R-Tree
类型:MyISAM
引擎支持,也就是空间索引的默认结构类型。T-Tree
类型:NDB-Cluster
引擎支持,主要用于MySQL-Cluster
服务中。
在上述的几种索引结构中,B+
树和哈希索引是最常见的索引结构,几乎大部分存储引擎都实现了,对于后续两种索引结构在某些情况下也较为常见,但除开列出的几种索引结构外,MySQL
索引支持的数据结构还有R+、R*、QR、SS、X
树等结构。
但为何后续的一些索引结构大家没听说过呢?这是因为索引到底支持什么数据结构,这是由存储引擎决定的,不同的存储引擎支持的索引结构也并不同,目前较为常用的引擎就是
MyISAM、InnoDB
,因此大家未曾听说后面列出的这些索引结构也是正常的。
当然,也正因为索引结构由存储引擎决定,而MySQL
引擎层在《MySQL架构篇》中提到过,属于可拔插式引擎,所以如果你有能力自己实现一个引擎,那你甚至可以让引擎的索引机制支持任何数据结构。
在
MySQL
中创建索引时,其默认的数据结构就为B+Tree
,如何更换索引的数据结构呢?如下:
CREATE INDEX indexName ON tableName (columnName(length) [ASC|DESC]) USING HASH;
也就是在创建索引时,通过USING
关键字显示指定索引的数据结构(必须要为当前引擎支持的结构)。
同时索引会被分为有序索引和无序索引,这是指索引文件中存储索引节点时,会不会按照字段值去排序。那一个索引到底是有序还是无序,就是依据数据结构决定的,例如B+Tree、R-Tree
等树结构都是有序,而哈希结构则是无序的。
1.2、字段数量层次
前面从索引的数据结构层次出发,可以将索引分为不同结构的类型,而从表字段的层次来看,索引又可以分为单列索引和多列索引,这两个称呼也比较好理解,单列索引是指索引是基于一个字段建立的,多列索引则是指由多个字段组合建立的索引。
单列索引也会分为很多类型,比如:
- 唯一索引:指索引中的索引节点值不允许重复,一般配合唯一约束使用。
- 主键索引:主键索引是一种特殊的唯一索引,和普通唯一索引的区别在于不允许有空值。
- 普通索引:通过
KEY、INDEX
关键字创建的索引就是这个类型,没啥限制,单纯的可以让查询快一点。 - .....还有很多很多,只要是基于单个字段建立的索引都可以被称为单列索引。
多列索引的概念前面解释过了,不过它也有很多种叫法,例如:
- 组合索引、联合索引、复合索引、多值索引....
但不管名称咋变,描述的含义都是相同的,即由多个字段组合建立的索引。
不过在使用多列索引时要注意:当建立多列索引后,一条
SELECT
语句,只有当查询条件中了包含了多列索引的第一个字段时,才能使用多列索引,下面举个栗子。
比如在用户表中,通过id、name、age
三个字段建立一个多列索引,什么情况下会使用索引,什么时候不会呢?如下:
-- 无法使用多列索引的SQL语句
SELECT * FROM `zz_user` WHERE name = "竹子" AND age = "18";
-- 能命中多列索引的SQL语句
SELECT * FROM `zz_user` WHERE name = "竹子" AND id = 6;
OK,到这里就根据字段数量的层面出发,简单讲明了单列和多列索引的概念,但无论是单列还是多列,都可以存在一个前缀索引的概念,啥叫前缀索引呢?还记得创建索引时指定的length
字段吗?
length
:如果字段存储的值过长,选用值的前多少个字符创建索引。
使用一个字段值中的前N
个字符创建出的索引,就可以被称为前缀索引,前缀索引能够在很大程度上,节省索引文件的存储空间,也能很大程度上提升索引的性能,这是为什么呢?后面分析索引实现原理的时候细聊。
1.3、功能逻辑层次
相信大家在面试时,如果问到了MySQL
索引机制,相信一定会问如下这道面试题:
请回答一下你知道的
MySQL
索引类型。
这题的答案该怎么回答呢?其实主要就是指MySQL
索引从逻辑上可以分为那些类型,以功能逻辑划分索引类型,这也是最常见的划分方式,从这个维度来看主要可划分为五种:
- 普通索引、唯一索引、主键索引、全文索引、空间索引
对于普通索引、唯一索引、主键索引都介绍过了,就不再过多阐述,但稍微提一嘴,在主键字段上建立的索引被称为主键索引,非主键字段上建立的索引一般被称为辅助索引或、二级索引或次级索引,接着重点聊一下全文索引和空间索引。
全文索引和空间索引都是MySQL5.7
版本后开始支持的索引类型,不过这两种索引都只有MyISAM
引擎支持,其他引擎要么我没用过,要么就由于自身实现的原因不支持,例如InnoDB
。对于全文索引而言,其实在MySQL5.6
版本中就有了,但当时并不支持汉字检索,到了5.7.6
版本的时候才内嵌ngram
全文解析器,才支持亚洲语种的分词,同时InnoDB
引擎也开始支持全文索引,在5.7
版本之前,只有MyISAM
引擎支持。
全文索引
全文索引类似于ES、Solr
搜索中间件中的分词器,或者说和之前常用的like+%
模糊查询很类似,它只能创建在CHAR、VARCHAR、TEXT
等这些文本类型字段上,而且使用全文索引查询时,条件字符数量必须大于3
才生效。当然,还是举个栗子才有感觉:
+------------+--------------------------------------------+------------------+
| article_id | article_name | special_column |
+------------+--------------------------------------------+------------------+
| 1 | MySQL架构篇:自顶向下深入剖析MySQL整体架构 | 《全解MySQL》 |
| 2 | MySQL执行篇:一条SQL语句从诞生至结束的历程 | 《全解MySQL》 |
| 3 | MySQL设计篇:数据库六范式与反范式设计准则!| 《全解MySQL》 |
| 4 | MySQL索引篇:索引概述、分类及建立索引的原则| 《全解MySQL》 |
+------------+--------------------------------------------+------------------+
比如现在用户想要搜索一篇文章,但是忘记文章全称了,只记得「诞生至结束」这个词汇,此时用户搜索这个词汇,走全文索引的情况下,照样能够定位到上表中的第二条记录。
当然,全文索引如何创建与使用,待会儿后面一起列出来。
空间索引
空间索引这玩意儿其实用的不多,至少大部分项目的业务中不会用到,想要弄清楚空间索引,那么首先得知道一个概念:GIS
空间数据,GIS
是什么意思呢?是地理信息系统,这是一门新的学科,基于了计算机、信息学、地理学等多科构建的,主要就是用于管理地理信息的数据结构,在国土、规划、出行、配送、地图等和地理有关的项目中,应用较为频繁。
地理空间数据主要包含矢量数据、3D模型、影像文件、坐标数据等,说简单点,空间数据也就是可以将地理信息以模型的方式,在地图上标注出来。在MySQL
中总共支持GEOMETRY、POINT、LINESTRING、POLYGON
四种空间数据类型,而空间索引则是基于这些类型的字段建立的,也就是可以帮助我们快捷检索空间数据。
不过对于空间索引,一般用的较少,大家了解即可。
1.4、存储方式层次
上面聊完了三种不同层次的索引划分后,接着从存储方式的层面再聊聊,从存储方式来看,MySQL
的索引主要可分为两大类:
- 聚簇索引:也被称为聚集索引、簇类索引
- 非聚簇索引:也叫非聚集索引、非簇类索引、二级索引、辅助索引、次级索引
重点说一说这两类索引存储方式的区别,在说之前先回忆一下数组和链表的区别:
- 数组是物理空间上的连续,存储的所有元素都会按序存放在同一块内存区域中。
- 链表是逻辑上的连续,存储的所有元素可能不在同一块内存,元素之间以指针连接。
为啥要说这个呢?因为聚簇索引和非聚簇索引的区别也大致是相同的:
- 聚簇索引:逻辑上连续且物理空间上的连续。
- 非聚簇索引:逻辑上的连续,物理空间上不连续。
当然,这里的连续和数组不同,因为索引大部分都是使用B+Tree
结构存储,所以在磁盘中数据是以树结构存放的,所以连续并不是指索引节点,而是指索引数据和表数据,也就是说聚簇索引中,索引数据和表数据在磁盘中的位置是一起的,而非聚簇索引则是分开的,索引节点和表数据之间,用物理地址的方式维护两者的联系。
不过一张表中只能存在一个聚簇索引,一般都会选用主键作为聚簇索引,其他字段上建立的索引都属于非聚簇索引,或者称之为辅助索引、次级索引。但也不要走进一个误区,虽然MySQL
默认会使用主键上建立的索引作为聚簇索引,但也可以指定其他字段上的索引为聚簇索引,一般聚簇索引要求索引必须是非空唯一索引才行。
其实就算表中没有定义主键,
InnoDB
中会选择一个唯一的非空索引作为聚簇索引,但如果非空唯一索引也不存在,InnoDB
隐式定义一个主键来作为聚簇索引。
当然,主键或者说聚簇索引,一般适合采用带有自增性的顺序值。
对于聚簇、非聚簇索引的区别、两者的查找过程、隐式主键、为何主键适合自增值等这些问题,在后续的《索引原理篇》中会详细讲解。
1.5、索引分类小结
至此,对于MySQL
“多样化”的索引机制,一大堆索引名词,就已经梳理清楚啦!相信到这里为止,大家也对MySQL
的索引机制有了系统化的认知,其实最开始给出的一大堆索引名词,只是从不同角度划分出来的,在上述中分别从数据结构、字段数量、功能逻辑以及存储方式多个层面进行了描述。当然,要牢记的是,以功能逻辑的层次来划分索引,这也是最常用的方式。