【MySQL索引学习】MySQL索引详细学习

一、什么是索引

索引是一种用于快速查询和检索数据的数据结构。 可以将其类比于书的目录。

索引底层的数据结构存在很多种类型,常见的索引结构有: B 树, B+树 和 Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyIsam,都使用了 B+树作为索引结构。

二、索引的优缺点

优点:

  • 使用索引可以大大加快 数据的检索速度 (大大减少检索的数据量), 这也是创建索引的最主要的原因
  • 通过创建唯一性索引 ,可以保证数据库表中每一行数据的唯一性

缺点:

  • 创建索引和维护索引会消耗时间。当对表中数据进行增、删、改的时候,如果数据有索引,那么索引也需要动态修改,会降低SQL的执行效率。
  • 索引需要使用物理文件存储,会消耗一定的物理空间。

(我们思考这样一个问题:使用索引一定能提高查询性能吗?

大多数情况下,索引查询都是比全表扫描要快的。但是如果数据库的数据量不大,那么使用索引也不一定能够带来很大提升。)

三、Mysql为什么使用B+树做索引?

Mysql默认使用的是Innodb引擎 ,当然MySQL也支持其他的存储引擎如MyISAM等,无论是Innodb还是MyISAM都是使用了B+树作为索引结构,下面我们来分析下索引底层数据结构选型,为什么使用B+树做索引?

(一)为什么不用Hash表?

哈希表存储的元素是键值对,通过键(key)即可快速取出对应的值(value),因此哈希表可以快速检索数据(接近 O(1))。

既然哈希表这么快,为什么 MySQL 没有使用其作为索引的数据结构呢?

主要是因为 Hash 索引不支持顺序和范围查询 。假如我们要对表中的数据进行排序或者进行范围查询,那 Hash 索引可就不行了。并且,每次 IO 只能取一个

(试想一种情况:

java 复制代码
SELECT * FROM tb1 WHERE id < 1000;

在这种范围查询中,优势非常大,直接遍历比 1000 小的叶子节点就够了。而 Hash 索引是根据 hash 算法来定位的,难不成还要把 1 - 999 的数据,每个都进行一次 hash 计算来定位吗?这就是 Hash 最大的缺点了。

(二)为什么不使用二叉查找树

二叉查找树 (Binary Search Tree)是一种基于二叉树的数据结构,它具有以下特点:

  • 左子树所有节点的值均小于根节点的值。
  • 右子树所有节点的值均大于根节点的值。
  • 左右子树也分别为二叉查找树。

当二叉查找树是平衡的时候,也就是树的每个节点的左右子树深度相差不超过 1 的时候,查询的时间复杂度为 O(log2(N)),具有比较高的效率。然而,当二叉查找树不平衡时,例如在最坏情况下(有序插入节点),树会退化成线性链表 (也被称为斜树),导致查询效率急剧下降,时间复杂退化为 O(N)。

也就是说,二叉查找树的性能非常依赖于它的平衡程度 ,这就导致其不适合作为 MySQL 底层索引的数据结构。

(三)为什么不使用AVL(平衡二叉树) 树

平衡二叉树(AVL 树)是计算机科学中最早被发明的自平衡二叉查找树AVL 树的特点是保证任何节点的左右子树高度之差不超过 1 ,因此也被称为高度平衡二叉树 ,它的查找、插入和删除 在平均和最坏情况下的时间复杂度都是 O(logn)

那为什么不使用AVL树作为索引呢?原因有如下两点:

  • 1、AVL树是高度平衡的二叉树,需要频繁地进行旋转操作 来保持平衡,因此会有较大的计算开销进而降低了查询性能
  • 2、在使用 AVL 树时,每个树节点仅存储一个数据 ,而每次进行磁盘 IO 时只能读取一个节点的数据,磁盘 IO 是一项耗时的操作,而我们在设计数据库时需要最大限度地减少磁盘 IO 操作的次数。

(四)为什么不用红黑树

红黑树是一种自平衡二叉查找树,通过在插入和删除节点时进行颜色变换和旋转操作,使得树始终保持平衡状态。和 AVL 树不同的是,红黑树并不追求严格的平衡,而是大致的平衡。

红黑树的应用还是比较广泛的,例如 JDK1.8 的 HashMap 底层用到了红黑树。对于数据在内存中的这种情况来说,红黑树的表现是非常优异的。

但为什么不会用红黑树来作为索引呢?

原因:

在使用红黑树时,每个树节点仅存储一个数据 ,而每次进行磁盘 IO 时只能读取一个节点的数据,磁盘 IO 是一项耗时的操作,而我们在设计数据库时需要最大限度地减少磁盘 IO 操作的次数。

(五)B树 & B+树

B 树也称 B-树,全称为 多路平衡查找树 。B+树是B树的一种变化。

目前大部分数据库系统及文件系统都采用 B-Tree 或其变种 B+Tree 作为索引结构。

B树 和 B+树有何异同?Mysql的InnoDB 和 MyISAM 引擎为何都选用B+树作为索引结构?(***)

概述:

  • 1、B+树的磁盘IO次数更少。B+树非叶子节点只存储key,可以存放更多的键值。
  • 2、B+树叶子节点间是通过双向链表连接,便于顺序查找。
  • 3、B+树支持顺序查找、范围查找、分组查找更容易
  • 4、B+树查找效率稳定。任何查找都是从根节点到叶子节点的过程。

详细分析:

  • B 树的所有节点既存放键(key) 也存放数据(data),而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key。(这样。如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少,数据查询的效率也会更快。)
  • B 树的叶子节点都是独立的;B+树中各个叶子节点之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。
  • B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而B树因为数据分散在各个节点,要实现这一点是很不容易的。
  • B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显

综上,B+树与B树相比,其查找过程IO次数更少,且具备更稳定的查询效率和范围查询这些优势。

(附加:

在MySQL中,InnoDB引擎和MyISAM引擎都是使用B+树作为索引结构,但两者的实现方式不太一样:

  • 在InnoDB引擎中主键索引使用的是聚簇索引非主键索引(二级索引)使用的是非聚簇索引
  • MyISAM引擎中无论是主键索引还是非主键索引使用的都是非聚簇索引

四、聚簇索引和非聚簇索引

(一)聚簇索引

聚簇索引索引和数据一起存放的 索引。即聚簇索引的每个非叶子节点 存储的是索引 ,而每个叶子节点 存储的是索引和索引对应的数据

主键索引 其就是聚簇索引

优点:

  • 1、查询速度非常块。因为聚簇索引(即主键索引)其是基于B+树这种数据结构,其非叶子节点存储的是主键索引,而非叶子节点存储的是主键索引及其对应的数据。只要定位到了节点就相当于找到了这条数据,其相比与非聚簇索引少了回表或是查找数据文件这些操作。
  • 2、对于排序查找和范围查找更加友好。聚簇索引是有序的,其叶子节点是有序的,对于主键的排序查找和范围查找的速度非常快。

缺点:

  • 1、依赖于有序的数据。因为B+树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入的时候进行排序,这样对于插入和查找的效率就肯定会慢。
  • 2、更新代价大。对于聚簇索引,在修改其索引时候,因为其叶子节点不仅存储了索引同时也存储了数据,这样其修改代价肯定是较大的。(对于主键索引来说,主键一般是不可被修改的)。

聚簇索引查找流程示意图如下:

(二)非聚簇索引

非聚簇索引索引和数据分开存放的 。即非聚簇索引的每个非叶子节点 存放的是也是索引 ,但叶子节点 存放的却是数据的指针或是主键。(当查询到索引对应的指针或是主键后,还需要根据指针或是主键再到数据文件或是表中进行查询)

非主键索引 (二级索引即辅助索引)就是非聚簇索引

优点:

  • 更新代价比聚簇索引要小 。非聚簇索引的更新代价就没有聚簇索引那么大了,非聚簇索引的叶子节点是不存放数据的

缺点:

  • 1、依赖于数据的有序性。和聚簇索引一样非聚簇索引也依赖于数据的有序性。
  • 2、可能会二次查询或回表。这应该是非聚簇索引最大的缺点了。 当查到索引对应的指针或主键后,可能还需要根据指针或主键再到数据文件或表中查询。

非聚簇索引查找流程如下:

五、主键索引 和 二级索引

(一)主键索引

数据表中主键使用的就是主键索引。

一张数据表有只能有一个主键,并且主键不能为 null,不能重复。

在 MySQL 的 InnoDB 的表中,当没有显示的指定表的主键时,InnoDB 会自动先检查表中是否有唯一索引且不允许存在 null 值的字段,如果有,则选择该字段为默认的主键,否则 InnoDB 将会自动创建一个 6Byte 的自增主键。

主键索引 就属于聚簇索引,其叶子节点data存放的是主键及主键对于的完整的数据。

(二)二级索引

二级索引 (Secondary Index)又称为辅助索引 ,是因为二级索引的叶子节点存储的数据是主键。也就是说,通过二级索引,可以定位主键的位置。(然后通过回表进而查询到索引对应的数据)

唯一索引普通索引前缀索引 等索引属于二级索引。

其中:

  • 1、唯一索引(Unique Key) :唯一索引也是一种约束。唯一索引的属性列不能出现重复的数据,但是允许数据为 NULL(主键索引是不允许数据为NULL),一张表允许创建多个唯一索引。 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。
  • 2、普通索引(Index) :普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和 NULL。
  • 3、前缀索引(Prefix) :前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。

六、覆盖索引

我们前面说了二级索引,非聚簇索引的叶子节点存储的是主键的值,通过索引可以定位主键的位置。(然后通过回表进而查询到索引对应的数据)。那非聚簇索引一定回表查询吗(覆盖索引)?

非聚簇索引不一定回表查询。

试想一种情况,用户准备使用 SQL 查询用户名,而用户名字段正好建立了索引。

java 复制代码
SELECT name FROM table WHERE name='AAA';

那么这个索引的 key 本身就是 name,查到对应的 name 直接返回就行了,无需回表查询。

覆盖索引

如果一个索引包含(或者说覆盖 )所有需要查询的字段的值,我们就称之为 覆盖索引(Covering Index)

覆盖索引即需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了,而无需回表查询。

(注意:
覆盖索引是索引优化的一种常用手段(重点)。
由于覆盖索引的索引即为所要查询的字段的数据,无需进行回表查询,减少了树的搜索次数,显著提高了查询性能,所以使用覆盖索引是索引优化的一种常用手段

七、联合索引

联合索引,即使用表中的多个字段创建索引,就是 联合索引

以 score 和 name 两个字段建立联合索引:

java 复制代码
ALTER TABLE `Student_Grade` ADD INDEX id_score_name(score, name);

最左前缀匹配原则

最左前缀匹配原则指的是,在使用联合索引时,MySQL 会根据联合索引中的字段顺序,从左到右依次到查询条件中去匹配,如果查询条件中存在与联合索引中最左侧字段相匹配的字段,则就会使用该字段过滤一批数据,直至联合索引中全部字段匹配完成,

如果最左边的字段不能完全匹配,那么会依次向右移动,对下一个字段进行匹配,直到所有的字段都被匹配或者无法找到匹配项为止。

所以,我们在使用联合索引时,可以将区分度高的字段放在最左边,这也可以过滤更多数据。

八、索引下推

索引下推:是MySQL5.6版本的新特性 ,用于优化数据查询。当存储引擎通过索引检索到数据并返回给MySQL服务器时,服务器会判断数据是否符合条件。在使用索引条件下推优化时,如果存在某些被索引的列的判断条件,MySQL服务器将这一部分判断条件传递给存储引擎,由存储引擎通过判断索引是否符合MySQL服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给MySQL服务器。

这种优化可以减少存储引擎查询基础表的次数 ,也可以减少MySQL服务器从存储引擎接收数据的次数,从而提高了查询效率 。简单来说,索引下推就是将原本由上层(服务层)负责的部分任务交给了下层(引擎层)去处理

相关推荐
Python私教2 小时前
model中能定义字段声明不存储到数据库吗
数据库·oracle
Red Red4 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
mqiqe5 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
工业甲酰苯胺5 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
BestandW1shEs5 小时前
谈谈Mysql的常见基础问题
数据库·mysql
重生之Java开发工程师5 小时前
MySQL中的CAST类型转换函数
数据库·sql·mysql
教练、我想打篮球5 小时前
66 mysql 的 表自增长锁
数据库·mysql
Ljw...5 小时前
表的操作(MySQL)
数据库·mysql·表的操作
哥谭居民00015 小时前
MySQL的权限管理机制--授权表
数据库