索引 是[数据库]()里重要的组成部分,也是提高查询效率必备的知识点。本文将会介绍索引作用索引类型索引优化 以及索引底层结构 ,也算是对索引知识的一次归纳

一、索引介绍

什么是索引?

数据库 是用来存储与读取数据的,如何在这庞大的数据中查询我们想要的那一行呢?最简单的办法便是扫描 整个数据表,一一对比。然而这样效率太低了。

如果我们有类似字典 的功能,在查询某行数据前,先到字典里定位到行位置,再根据行位置找到具体数据,是否能更快呢?是的,索引就是这么设计的。

一般的,我们往表里插入某一行数据时,总会有额外的信息来定位到这一行。这个信息可能是一个指针地址 ,也可能是一个主键标识

在拿到这一行的定位信息 后,就可以将列数据和定位信息 做关联了。下次想查找这个字段列所对应的行数据时,就可以先到关联信息里搜索,拿到定位信息后直接查找即可。这就是索引,存储了列和定位信息,这定位信息也可以理解指向数据记录的引用指针

需要注意的是,索引是由存储引擎这个模块来实现的,不同的存储引擎有不同的实现方式。像innodb的主键就包含了行数据,找到了主键,也就找到了数据。

索引的分类

在数据库里,索引有好多种。我们可以从下面几方面来分类归纳。

从数据结构划分:B+树、hash索引、全文索引

从物理结构划分:聚集索引、非聚集索引

从逻辑用户划分:主键、唯一索引、复合索引、普通单列索引

其中,B+树、hash索引、全文索引将会在后面具体介绍其底层结构,我们来看看其他的索引:

聚集索引 :该索引除了存储索引信息还存储了行数据,像刚刚提到的主键就是。找到它也就意味找到数据了。并且它的排序直接对应了物理存储顺序。

非聚集索引 :该索引除了存储索引信息还存储了定位到数据记录的信息,需要根据这个信息再做一次查询,才能获取到数据,并且它的排序是逻辑上,不是物理存储顺序。

主键 :唯一地标识表中一条记录的索引,不能有NULL值。在InnoDB里,主键就是聚集索引。

唯一索引 :索引所对应的列值里是不能有重复值的,允许有NULL值。像刚刚提到的主键是不允许有NULL值的。

复合索引 :有多列组合在一起的索引,但只能按最左原则查找,即第一列字段才能被索引查找,后面只是作为附带信息存放着。主要是为了找到索引后,不需要再去行数据里捞数据,直接从索引里提取字段信息即可。

普通单列索引 :没有什么限制条件的索引列。

索引的缺点

引入索引,并不总意味着高效,它是需要付出代价维护的。每当有数据需要添加更新时,都得更新对应的索引,这是额外的性能开销,甚至有可能有出现死锁。

另外,索引是需要占用磁盘空间的,不能无限制的添加索引,要有针对性的建索引。

二、索引的使用

使用原则

索引之所以那么快,是因为我们将平时查询频率较高的字段单独维护了起来。当我们有多个查询选项,多个查询条件就不一定能发挥作用了,所以索引的使用是有注意事项的,下面总结了一些:

where里最经常用到的查询字段才建索引,能利用主键id,就用主键id来增删改查

按最左匹配原则,将多个单列索引改为复合索引,减少维护量

尽量挑选择度高,也就是重复率低的列作为索引,像性别这种列就不适合了,会在B+树里做多层次多范围的搜索,还不如全表扫描呢

查找时,不对索引列做函数计算,否则不能使用到索引

查询条件尽量用union来取代or

like用法:‘列%’这样还是可以用到索引的,'%列%'就不行了

ISNULL,ISNOTNULL是用不到索引的

在orderby,groupby里尽量使用索引字段

join的on条件里尽量使用索引字段

性能分析

当我们使用了索引后,又如何知道它有没有使用到索引呢?我们可以借助执行计划 来分析,执行计划是mysql根据我们的查询语句进行一系列的分析后得到的优化方案。我们可以通过执行计划来获取执行过程。

执行计划的获取:

explainselect语句

涉及的字段含义如下:

id:该SELECT标识符

select_type:该SELECT类型

table:输出行的表

partitions:匹配的分区

type:联接类型

possible_keys:可供选择的可能索引

key:实际选择的索引

key_len:所选密钥的长度

ref:与索引比较的列

rows:估计要检查的行数

filtered:按表条件过滤的行百分比

Extra:附加信息

其中,有个type字段,它的含义大概如下:

eq_ref:使用到了UNIQUE或PRIMARYKEY索引

ref:显示索引的哪一列被使用了

ref_or_null:对Null进行了索引优化

range:索引范围检索

index:索引扫描

unique_subquery:使用了in子查询,里面涉及了主键字段

index_subquery:使用了in子查询,里面涉及了非唯一索引

fulltext:全文索引

all:全表扫描数据

从上面大概就能分析出索引的使用情况了,如果是all,那就是没有用到索引了。

索引的的底层

前面提到过索引的种类时,细分了B+树、hash索引、全文索引这三类。现在我们来具体看下对应的底层结构吧。

B+树

在B+树之前还有二叉搜索树B树 ,我们来一步一步演化,看看有什么不同,先来看二叉搜索树

当要进行查找时,会按小于往左搜索,大于往右搜索的规则去寻找。二叉搜索树只存了单个节点值,树的高度有可能会很高,如果用来存储索引数据,效率将会降低,不适用于mysql的索引,我们来看看B树吧:

一个节点可以存储多个数据值。当然,在插入删除时需要做对应的拆分或合并动作。

而且B树允许在非叶子节点也存储具体数据,这意味着在扫描搜索时也会将数据加载进来,这无疑增加了磁盘IO。

对于磁盘IO要求高的mysql而言,B树也很不划算,所以B+树成了最好的选择,它长这样的:

B+树只在叶子节点 存储具体的数据(注:数据可以是真正的行数据也可以是定位到行数据的指针地址),而非叶子节点值只存放索引数据,这样可以降低磁盘IO,还能充分利用磁盘的预读功能,批量的加载索引数据。

hash索引

hash索引将列通过hash运算得到hashcode,然后将hashcode跟数据行的指针地址关联在一起,下次查找时只需查找对应hashcode的数据行地址即可。

hash索引非常的紧凑,查找速度很快,适用于内存存储引擎的应用。不过它只能精确查询,不支持范围查找,也不能直接进行排序。限制还是挺多的。

全文索引

全文索引主要是用于文档查找,像我们可能会从多篇文章中查找包含某些词语的文章,这时就可以使用全文索引了。虽然like也可以使用,但是效率太低了。

全文索引在接收到文档时,会对它进行分词处理,以获取到关键词。然后会将关键词和属于这个文档的id关联起来。

下次查找,就会先到关键词列表里找到关联的文档id,最后利用文档id去查找到文档数据。

总结

索引所涉及的知识点还是挺多的,从了解索引用好索引 再到优化索引 ,我想这应该是我们进行查询优化的必经之路吧。希望本文能为大家带来不一样的认识,也欢迎一起探讨!

最后修改:2021 年 11 月 02 日
如果觉得我的文章对你有用,请随意赞赏