MySQL - 深入解析MySQL索引数据结构

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: MySQL - 深入解析MySQL索引数据结构

MySQL官方对索引定义:是存储引擎用于快速查找记录的一种数据结构。需要额外开辟空间和数据维护工作。

  • 索引是针对表来说的,不是针对数据库来说的(建表的sql语句中的index就是索引);
  • 索引是物理数据页存储,在数据文件中(InnoDB,ibd文件),利用数据页(page)存储;
  • 索引可以加快检索速度,但是同时也会降低增删改操作速度,索引维护需要代价。

先介绍一款可以帮助理解数据结构的网站:Data Structure Visualizations

1. 索引的数据结构演进

1.1 链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

有一张用户表,有id、username、password三个字段。现在对这个表进行查询。

假设上表中的数据存储在链表上,执行以下SQL我们可以发现影响查询速度的是这条数据在第几行

-- 查找1次
select * from user where password = 123;
-- 查找2次
select * from user where password = 234;
-- 查找3次
select * from user where password = 78;
-- 查找4次
select * from user where password = 567;
-- 查找5次
select * from user where password = 70;
-- 查找6次
select * from user where password = 379;

假设表中有1000万条数据,现在要查询第1000万条数据,这样就需要查找1000万次。顺序查找的问题是存储数据的结构是线性的,也就是说想要查询第2条数据,我需要知道第1条数据是什么。 大家可能会考虑到为什么不要数组,直接通过下标就可以查到数据,问题是数组是固定长度的,那么数组长度定义为多少合适呢?

1.2 二叉树

要解决链表的问题,我们可以用来解决,先来看一下二叉树:二叉树是一种特殊的树,每个节点最多有两个子节点,值从左到右依次递增。

二叉搜索树通过增加了一条搜索路径,提高了查询效率,查找的效率取决于树的深度(高度)

  • 问:为什么索引的数据结构不用二叉树?

因为当值依次递增插入时,二叉树会退化成链表,对加快查询没有任何作用。

时间复杂度(代码执行的次数):O(N)

1.3 红黑树(自平衡二叉查找树)

特点:

  1. 每个节点只能是红色或黑色;
  2. 跟节点必须是黑色;
  3. 红色的节点,它的叶节点只能是黑色;
  4. 从任一节点到其叶子节点的所有路径都包含相同数目的黑色节点。

为了解决二叉树变成链表的问题,出现了红黑树。当数据插入时,红黑树通过旋转和变色来达到平衡。这样就弥补了二叉树退化成链表的尴尬。 平衡后树的高度就变成了4层,相比于二叉树,效率更高。

  • 问:为什么索引的数据结构不用红黑树?

因为当值依次递增插入时树的高度会变得特别高。就例如上图查询0009只用4次,那查询1000万呢?树的高度大概是24,最坏的情况需要查找24次!查找24次是概念呢?,MySQL存储数据是存文件的,每次查找都需要读一次文件到内存,即最坏的查询情况需要读24次文件到内存,也就是24次IO操作,这是非常耗时的。

时间复杂度为:O(log2N)

1.4 B树(多路平衡搜索树)

特点:

  1. 索引值和data数据分布在整棵树结构中
  2. 每个节点可以存放多个索引值及对应的data数据
  3. 树节点中的多个索引值从左到右升序排列

B树的搜索:从根节点开始,对节点内的索引值序列采用二分法查找,如果命中就结束查找。没有命中会进入子节点重复查找过程,直到所对应的的节点指针为空,或已经是叶子节点了才结束。

因为树的高度问题,出现了B树(多路平衡搜索树),B树的思路是多叉树。只要分叉越多,那么每一层可以存放的元素就越多,树的层级自然而然就会降低。那么分叉肯定是越多越好,最多可以多到什么程度呢?这取决于MySQL一页可存储的数据量是多少,我们可以通过SQL命令来查询:

show global status like 'Innodb_page_size';

可以看到MySQL默认一页是16384字节,大约是16kb。假设一条数据1KB为例,一颗高度为3的B树,可以存储的数据个数是 16 * 16 * 16 = 4096

问:为什么索引的数据结构不用B树?

虽然B树相对于红黑树,树的高度降低了,但是随着数据量的增多,树的高度还是会变得很高,效率会变得特别低。而且对范围查找也不方便。

1.5 B+树

特点:

  1. 非叶子节点不存储data数据,只存储索引值,这样便于存储更多的索引值
  2. 叶子节点包含了所有的索引值和data数据
  3. 叶子节点用指针连接,提高区间的访问性能

相比B树,B+树进行范围查找时,只需要查找定位两个节点的索引值,然后利用叶子节点的指针进行遍历即可。而B树需要遍历范围内所有的节点和数据,显然B+Tree效率高。

1.6 哈希

Hash 底层实现是由 Hash 表来实现的,是根据键值 <key, value> 存储数据的结构。非常适合根据key查找 value 值,也就是单个 key 查询,或者说等值查询。其结构如下所示:

从上面结构可以看出,Hash索引可以方便的提供等值查询,但是对于范围查询就需要全表扫描了。Hash索引在MySQL 中Hash结构主要应用在Memory原生的Hash索引 、InnoDB 自适应哈希索引。

InnoDB提供的自适应哈希索引功能强大,接下来重点描述下InnoDB 自适应哈希索引。

InnoDB自适应哈希索引是为了提升查询效率,InnoDB存储引擎会监控表上各个索引页的查询,当InnoDB注意到某些索引值访问非常频繁时,会在内存中基于B+Tree索引再创建一个哈希索引,使得内存中的 B+Tree 索引具备哈希索引的功能,即能够快速定值访问频繁访问的索引页。

InnoDB自适应哈希索引:在使用Hash索引访问时,一次性查找就能定位数据,等值查询效率要优于B+Tree。

自适应哈希索引的建立使得InnoDB存储引擎能自动根据索引页访问的频率和模式自动地为某些热点页建立哈希索引来加速访问。另外InnoDB自适应哈希索引的功能,用户只能选择开启或关闭功能,无法进行人工干涉。

show engine innodb status \G; 
show variables like '%innodb_adaptive%';

2. 总结

  • 为什么mysql使用的是B+树

准确的表述:为什么mysql的InnoDB和MyISAM存储引擎的索引使用的是B+树

  1. hash表,等值查询是很快的,但是不满足常用的范围查找且相邻的两个值之间没有关系,而且hash比较消耗内存。
  2. 二叉树/平衡二叉树/红黑树等都是有且仅有2个分支,共性就是数据量大的时候树的深度变深,增加IO的次数。
  3. B树会在节点上存储数据,这样一页存放的key的数量就会减少,增加树的深度。
  4. B+树中非叶子节点去除了数据,这样就会页中key的数量,而且叶子节点之间是通过链表相连,有利于范围查找和分页。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
11天前
|
缓存 关系型数据库 MySQL
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?
|
11天前
|
SQL 关系型数据库 MySQL
MySQL索引你用对了吗?
本文从遇到的问题出发,分析了tddl优化器、MySQL索引、分表拆分键的选择相关知识。
|
12天前
|
存储 关系型数据库 MySQL
MySQL bit类型增加索引后查询结果不正确案例浅析
【8月更文挑战第17天】在MySQL中,`BIT`类型字段在添加索引后可能出现查询结果异常。表现为查询结果与预期不符,如返回错误记录或遗漏部分数据。原因包括索引使用不当、数据存储及比较问题,以及索引创建时未充分考虑`BIT`特性。解决方法涉及正确运用索引、理解`BIT`的存储和比较机制,以及合理创建索引以覆盖各种查询条件。通过`EXPLAIN`分析执行计划可帮助诊断和优化查询。
|
15天前
|
SQL 存储 关系型数据库
mysql加索引真的会锁表吗?揭秘背后的技术细节与规避策略
【8月更文挑战第16天】在数据库管理中,添加索引能大幅提升查询效率。MySQL执行此操作时的锁定行为常引起关注。文章详细解析MySQL中索引添加时的锁定机制及其原理。不同存储引擎及SQL语句影响锁定策略:MyISAM需全表锁定;InnoDB提供更灵活选项,如使用`ALTER TABLE... LOCK=NONE`可在加索引时允许读写访问,尽管可能延长索引构建时间。自MySQL 5.6起,在线DDL技术可进一步减少锁定时间,通过`ALGORITHM=INPLACE`和`LOCK=NONE`实现近乎无锁的表结构变更。合理配置这些选项有助于最小化对业务的影响并保持数据库高效运行。
30 4
|
15天前
|
存储 SQL 关系型数据库
深入解析MySQL事务机制和锁机制
深入解析MySQL事务机制和锁机制
|
15天前
|
SQL JavaScript 关系型数据库
Mysql索引不当引发死锁问题
本文通过真实案例解析了MySQL在高并发环境下出现死锁的问题。数据库表`t_award`包含多个索引,但在执行特定SQL语句时遭遇索引失效,导致更新操作变慢并引发死锁。分析发现,联合索引`(pool_id, identifier, status, is_redeemed)`因`identifier`允许为空值而导致索引部分失效。此外,`pool_id`上的普通索引产生的间隙锁在高并发下加剧了死锁风险。为解决此问题,文中提出了调整索引顺序至`(pool_id, status, is_redeemed, identifier)`等方案来优化索引使用,进而减轻死锁现象。
|
17天前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
1天前
|
SQL 关系型数据库 MySQL
深入探索MySQL索引策略
本文旨在深入探讨MySQL(8.0.26)数据库中索引的设计与优化方法。
|
2月前
|
存储 SQL 关系型数据库
(六)MySQL索引原理篇:深入数据库底层揭开索引机制的神秘面纱!
《索引原理篇》它现在终于来了!但对于索引原理及底层实现,相信大家多多少少都有了解过,毕竟这也是面试过程中出现次数较为频繁的一个技术点。在本文中就来一窥`MySQL`索引底层的神秘面纱!
137 5
|
8天前
|
SQL 算法 关系型数据库
MySQL索引看这篇就行
MySQL索引看这篇就行
13 0

推荐镜像

更多
下一篇
云函数