文章目录
- 索引
- 引言
- 常见的索引
- 哈希索引
- 自适应哈希索引
- B+树索引
- 聚集索引
- 非聚集索引
- 使用方法
- 联合索引
- 最左前缀匹配规则
- 覆盖索引
- 全文索引
- 使用方法
索引
引言
为什么需要索引?
倘若不使用索引,查找数据时,MySQL必须遍历整个表。而表越大,查询的时间则越长,则数据库的效率也就越低。而索引就类似于书籍的目录,可以帮助我们快速的定位、检索到需要的数据行,对提高数据库的性能有着很大的帮助。
在MySQL中,索引是一种特殊的文件,其中包含着对数据表里所有记录的引用指针。各类索引有各自的数据结构实现。
索引优缺点
优点:
- 大大加快了数据检索的速度
- 使用要求低,所有的列类型都可以被索引,也就是可以给任意字段设置索引
缺点:
- 索引需要占用物理空间,建立的索引越多则需要的空间越大。
- 创建和维护索引需要耗费时间,并且时间随着数据量的增加而增加。
- 当对表中的数据进行增加、删除、修改的时候,索引也要动态的维护,如果一张表经常需要增删改,那么有索引的话就降低了数据的更新速度。
适用场景
- 数据量较大,并且经常对这些列进行查询。
- 该数据库表的插入、修改操作频率较低。
常见的索引
因为 MySQL
中索引是在 存储引擎层 实现的,所以并没有统一的索引标准,换言之:
- 不同存储引擎支持的索引类型并不一样。
- 而即使多个存储引擎支持同一种类型的索引,其底层的实现也可能不同。
由于 InnoDB存储引擎
在 MySQL
数据库中使用最为广泛,所以下面的讨论主要以 InnoDB
为例。
在 InnoDB存储引擎
中,主要支持以下三种常见的索引:B+树索引、哈希索引、全文索引。
哈希索引
如不了解哈希可移步哈希 :哈希冲突、负载因子、哈希函数、哈希表、哈希桶
原理:通过除留余数法将键值转换为哈希值,并将数据存储对应的槽中,如果出现了哈希冲突,则使用链地址法进行解决,将数据插入对应槽中的链表。
由于哈希是直接通过哈希值来将数据映射到对应位置,所以哈希索引对于等值查询的效率特别高,但是也正因为这个特性,使得哈希查找在面对范围查找的时候就毫无用武之地了。
自适应哈希索引
InnoDB存储引擎
会监控对表上各个索引页的查询,如果它观察到建立哈希索引可以带来速度提升,则会自行建立哈希索引,这也就是 自适应哈希索引。即会自动根据 访问频率和模式 来为 热点数据 建立哈希索引。
哈希索引是数据库自身自动创建并使用的,人工无法对其进行干预。
B+树索引
如不了解B+树可移步数据结构 | B树、B+树、B*树
比起哈希索引,B+树索引的优势主要在于排序查找以及区间查找。
在数据库中,B+树索引可以分为聚集索引(主键索引)和非聚集索引(辅助索引),它们之间的区别在于叶子节点中存放的是否是一整行的信息(即用户数据)
PS:叶子节点那一层存储的是表,而具体的某一个叶子节点才是存储列。
聚集索引
聚集索引其实就是索引和数据在同一个数据结构中。
由于 InnoDB存储引擎
中表的数据按照主键顺序存放,所以聚集索引也就是按照每张表的主键来构造出一颗B+树。由于数据真正的排序方式只能有一种,所以在每张表中只能存在着一个聚集索引。
这颗B+树的非叶子节点存放的是数据的索引,而叶子节点存放的即为整张表的行记录数据,所以我们通常也将叶子节点称为数据页,并且每个叶子节点之间用双向链表进行连接。
聚集索引对于主键的排序查找和范围查找速度非常快,并且由于叶子节点就是数据,所以只需要查找一次就可以得到结果。
非聚集索引
对于 非聚集索引(辅助索引) 来说,叶子节点并不包含行记录的全部数据,而是包含了主键的值。
也就是说,我们需要在非聚集索引中查找到主键,再通过主键在聚集索引中查找到具体的值,也就是需要两次查找。所以非聚集索引其实也就是一个二级索引。
基于以上特性,由于辅助索引的存在并不会影响数据在聚集索引中的存在方式,因此每张表中可以有多个辅助索引。
使用方法
创建主键约束(PRIMARY KEY)、唯一约束(UNIQUE)、外键约束(FOREIGN KEY)时,会自动创建对应列的索引。
查看索引
SHOW INDEX FROM 表名
创建
CREATE INDEX 索引名 ON 表名(字段名)
或者
ALTER TABLE 表名 ADD {KEY | INDEX} 索引名
删除
DROP INDEX 索引名 ON 表名
联合索引
联合索引即对表上的多个列进行索引:
联合索引和普通的B+树不同的地方在于它具有多个键值,键值按照从左往右的优先级以此对键值的大小进行排序,例如:上图有两个键值,首先会先按照第一个键值的大小进行排序,当第一个键相同时,再按照第二个键的大小进行排序。
因为以上特性,联合索引具有最左前缀匹配规则,当不满足规则时则不会使用联合索引,而是进行全索引扫描。
最左前缀匹配规则
就以上述数据进行举例,此时以键值 (a, b)
构建联合索引
SELECT * FROM TABLE WHERE a = xxx AND b = xxx 、
SELECT * FROM TABLE WHERE a = xxx
SELECT * FROM TABLE WHERE b = xxx
对于以上几条查询语句来说,虽然看起来差不多,但是效率却大相径庭。
对于前两句来说,它们是可以使用联合索引的,因为无论是按照 a
作为条件,或者是 a
和 b
作为条件。因为前面也说过了,联合索引的排序是按照从左往右优先的,所以当前两句都是优先根据 a
进行索引搜索,不会出现问题。
但对于 b=xxx
则无法适用以上性质,因为在联合索引中,后面的主键只有在前面的主键相同时才会具有有序性,而单独适用它的时候显然数据是无序的,所以这时只能进行全索引扫描。
对于范围查找也是这么一个道理,假设此时联合索引的主键为(a, b, c)
SELECT * FROM TABLE WHERE a > 3 AND b > 3
SELECT * FROM TABLE WHERE a > 3 AND b > 3 AND c > 3
SELECT * FROM TABLE WHERE a > 3 AND c > 3
同样按照上面的规则,前两种查询都可以适用联合索引,因为其遵循了从左至右的匹配原则,而第三条因为跳过了 b
,此时的数据是无序的,无法适用索引。
覆盖索引
覆盖索引即从辅助索引中就可以得到查询的记录,而不需要查询聚集索引中的记录。使用覆盖索引的一个好处就是由于辅助索引中不包含整行的所有记录,所以它的大小要远远小于聚集索引,因此可以减少大量的 I/O
操作。
由于辅助索引中叶子节点存放的数据就是主键,所以当我们要查找主键,或者通过主键来统计数量的时候,就可以使用覆盖索引来完成。
全文索引
在之前版本中只有 InnoDB
并不支持全文检索,而在 InnoDB1.2.x
版本之后,InnoDB
也加入了全文检索的功能。
全文索引即根据部分段落、句、词从数据库中查询除全文的技术,即根据部分查询词获取对应的文档。
主要依据倒排索引这一数据结构来实现,这一数据结构通常也在搜索引擎中进行使用。
这里就简要的介绍一下 InnoDB
中的倒排索引。其拥有两种表现形式:
inverted file index
(倒排文件索引)
表现形式 {单词, 单词所在的文档ID)full inverted index
(全文倒排索引)
表现形式{单词, (单词所在文档ID,在具体文档的位置)
例如我们存在以下数据:
并将其构建成 inverted file index(倒排文件索引)
的形式:
此时我们就建立起了各个单词与其对应文档的一个映射关系。
接着建立 full inverted index(全文倒排索引)
此时在之前的基础上,我们不仅确定了单词所在的文章,还确定了其所在文章中的对应位置,虽然比起 inverted file index来
说更加复杂,占据的空间也更多,但是却能更好的定位数据,并且扩充一些其它的搜索特性。
使用方法
创建全文索引
CREATE FULLTEXT INDEX 索引名 ON 表名(字段名);
查找方法
MATCH(要匹配的列) AGAINST(要查找的内容)
- 自然语言查询(
Natural Language
),即普通的包含关键词的搜索,例如:
SELECT * FROM (表名) WHERE MATCH(匹配列) AGAINST(查询内容)
Boolean
,这个模式允许使用IN BOOLEAN MODE修饰符
来进行全文检索,当使用该修饰符时,查询字符串的前后字符都会有特殊含义。例如+
和-
分别代表了该单词必须出现或者一定没出现。
这句查询即匹配包含 查询词1
并且不包含 查询词2
的结果:
SELECT * FROM 表名
WHERE MATCH (要匹配的列) AGAINST ('+查询词1 -查询词2' IN BOOLEAN MODE);
该模式所有选项如下:
全文查询的结果依据相关度进行降序排序,相关度计算依据如下:
- 查询词是否在文档中出现过
- 查询词在文档中出现的次数
- 查询词在索引列中的数量
- 包含查询词的文档数