【索引的数据结构】第2章节:InooDB和MyISAM索引结构对比

目录结构

之前整篇文章太长,阅读体验不好,将其拆分为几个子篇章。

本篇章讲解 InnoDB 和 MyISAM 索引结构对比。

InnoDB 的 B+Tree 索引注意事项

根页面位置万年不变

上述我们在索引迭代的过程中,为了更佳形象的描述,所以将顺序暂且定位自下而上,往上汇总目录项页。

但实际上 B+Tree 的形成是自上而下的,大致过程如下:

  • 每当为某张表创建一个 B+Tree 索引(聚簇索引不是人为创建的,创建表的时候默认创建),都会为这个索引创建一个 根节点页面。最开始表中没有数据的时候,每个 B+Tree 根节点中既没有用户记录,也没有目录项记录。
  • 随后向表中插入记录时,先把用户记录存储到这个 根节点中。
  • 当根节点中的 可用空间用完时,继续插入记录,此时存储引擎会将根节点中的所有记录复制一份到另一个新分配的页中,比如 页 a,然后对这个新页进行 页分裂的操作,得到另一个新的页,比如 页 b。这时候根据插入记录的键值(聚簇索引的话根据主键值,二级索引的话根据索引列值、主键值)的大小就会被分配到 页 a或者 页 b中,而根节点就升级为存储目录项的页。

特别注意:

一个 B+Tree 索引创建之后,它的根节点便不会再移动。

也就是对某个表创建索引之后,它的根节点的页号就会被存储在某个地方,然后凡是 InnoDB 存储引擎需要用到这个索引的时候,就会从那个固定的地方取出对应根节点的页号,从而来访问这个索引。

内节点中目录项记录的唯一性

我们知道 B+Tree 聚簇索引 的内节点中目录项记录的内容是 索引列 + 页号的组合,但是这个组合对于 非聚簇索引就不太适用,拿 test_table表举例,总共有三个字段:c1(主键)、c2、c3,假设这个表中有如下几行数据:

c1c2c3
11‘u’
31‘d’
51‘y’
71‘a’

当我们为 c2 列创建二级索引时,如果目录项页中的记录只是 索引列 + 页号的组合时,那么 c2列建立索引之后,B+Tree 的结构大致如下图所示:

B+Tree 数据结构组成如下:

  • 黄色方块为索引列的值
  • 蓝色方块为主键值
  • 红色方块为页码值

通过上图二级索引数据结构,我们可以看到页 3 作为一个目录项记录页,当二级索引列存在多个相同值的记录时,非叶子节点中的目录项只存储索引列 + 页号时,我们无法区分应该去哪个数据页查询数据,或者说当新增数据时:(9、1、'u'),对应表中的字段顺序为:c1、c2、c3,此时插入的 c2 列的值也为 1,在上述页 3 中存储的两条目录项记录的索引值都为 1,所有无法区分到底该插入哪个记录对应的页中。

为了解决问题,也就是说无论是实际记录还是目录项记录,都要实现唯一性,此时我们就可以把 主键值和索引列值一起存储在目录项记录中,如下图所示:

插入数据:(9、1、'u') 的执行过程应该如下图所示:

一个页面中至少存储两个记录

一个 B+Tree 只需要很少的层级就可以轻松存储数亿条记录,查询速度也是相当不错。

B+Tree 本质上就是一个大的多层级目录,每经过一个目录时就会过滤掉很多无效的子目录,最终会查找到存储真实数据的目录。

如果说一个大的目录中只存放一个子目录是啥效果?也就是会有很多层目录,并且我们从根节点开始查找,经过很多层目录之后,最后找到了一个目录,里面只存储了一条数据,你说气人不,费老大劲,经历了那么多次数据库 I/O,就查到一条数据,效率贼低。

所以说 InnoDB 存储引擎中的一个数据页至少存储两条记录

MyISAM 索引方案

MyISAM 索引的原理

MySQL 官方一般统称 B-Tree 为 B+树,适用于 B-Tree 的存储引擎如下表所示:

索引/存储引擎MyISAMInnoDBMemory
B-Tree 索引支持支持支持

虽然多个存储引擎都支持 B-Tree 索引,但是在底层的实现原理上却是不同的。

InnoDB 和 MyISAM 的底层默认使用 B-Tree 索引,而 Memory 底层默认使用 hash 索引。

InnoDB 的索引即数据:

  • 在聚簇索引的叶子节点中存储的是完整的数据:主键 + 数据
  • 在非聚簇索引的叶子节点中存储的数据是:索引列 + 主键

MyISAM 的索引虽然也是 B-Tree 结构,但是底层确实将 数据和索引分开单独存储

  • 数据文件(.myd 文件):存数据的文件,插入记录时,并没有按照主键大小刻意去排序,有多少塞多少
  • 索引文件(.myi 文件):MyISAM 为每张表的主键都创建一个 B-Tree 索引,但是叶子节点中存储的数据是:主键 + 地址

大致结构如下图所示:

索引组成结构:

  • 绿色方块为 主键值
  • 紫色方块为 地址偏移量

有一定我们要清楚,因为主键索引每一行记录都是唯一的,所以只需要存储 主键+地址即可,但是非主键列(二级索引)是不唯一的,很可能会重复,如果为非主键列创建索引,大致如下图所示:

这里康师傅应该是漏掉了二级索引数据重复的举例图,所以应该再加一个主键值,最终组成节点的机构为:

  • 叶子节点:索引列 + 主键 + 地址
  • 非叶子节点:索引列 + 主键 + 页码

MyISAM 和 InnoDB 的对比

  • MyISAM 中的索引都是 非聚簇索引,InnoDB 中包含两种索引 聚簇索引非聚簇索引
  • MyISAM 的叶子节点中存储的为 索引 + 地址,所以查询到地址之后,至少还需要一次回表查询;InnoDB 的聚簇索引叶子节点中的存储的是 完整的记录,所以根据主键查询可以直接返回,不需要回表查询
  • MyISAM 索引记录存储的是 地址,InnoDB 聚簇索引存储的是 主键 + 数据,非聚簇索引 data 域 存储的是 主键
  • MyIASM 回表查询的速度 非常快,因为叶子节点中查询到是数据的地址偏移量直接去文件中查找相当的快,而 InnoDB 叶子节点查到的是主键值,根据主键再去聚簇索引中查询数据,虽然也不慢,但是相比于用地址查询,还是差了点
  • MyISAM 可以没有主键;InnoDB 必须要有主键,如果没有显示指定,则 MySQL 自动选择一个 非空且能唯一标识记录的列作为主键,如果不存在这样的列,则会自动为 InnoDB 表生成一个 隐含字段 作为主键,字段长度为 6 个字节,类型为长整型。

索引的建议

为什么不建议使用过长的字段作为主键?

  • 因为二级索引节点中都会引用主键索引,过长的主键索引会导致二级索引树结构变的很臃肿
  • 用非单调的字段作为主键在 InnoDB 中不是一个好主意,已因为 InnoDB 索引本身是一颗 B+Tree,非单调的主键会导致在插入记录时,数据文件为了维护树的结构而频繁的进行 页分裂,导致性能比较低效,而使用 自增且单一的字段作为主键是个好的选择

InnoDB 和 MyISAM 索引分布对比如下图所示:

索引的代价

索引虽好,但不能乱建(劲酒虽好,但不能贪杯哦):

  • 占用空间:每个索引都要建立一棵 B+Tree,每个节点都是一个数据页,一个数据页为 16KB,一棵很大的 B+Tree 由很多个数据页组成,就会占用很大的空间
  • 消耗时间:对表进行 增删改操作时,都要去修改各个 B+Tree 的结构。因为 B+Tree 的 各个节点 都是根据索引列值 从小到达按顺序存储的而存储的 双向链表。而不论是叶子节点还是内节点(非叶子节点)中的记录都是按照索引列的值从小到达按顺序存储的而存储的 单向链表,所以如果对表记性 增删改的操作,会对各个节点和记录的排序造成破坏,存储引擎为了维护索引结构的平衡会进行额外的 记录移位页面分裂页面回收等操作,会造成性能大幅下降。

一个表中创建的索引越多,占用的空间越大。在增删改操作时,存储引擎维护索引消耗的时间就越多。

为了能建立好的索引,所以要根据数据的分布情况建立合理的索引结构。

本文内容总结借鉴于康师傅的 MySQL 视频课:https://www.bilibili.com/video/BV1iq4y1u7vj


在这里插入图片描述

一起学编程,让生活更随和!

如果你觉得是个同道中人,欢迎关注博主gzh:【随和的皮蛋桑】。

专注于Java基础、进阶、面试以及计算机基础知识分享🐳。偶尔认知思考、日常水文🐌。

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/285885.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习(二) -- 数据预处理(1)

系列文章目录 机器学习(一) -- 概述 机器学习(二) -- 数据预处理(1-3) 未完待续…… 目录 系列文章目录 前言 一、概述 二、数据获取 三、数据分布与趋势探查 1、散点图 2、折线图 3、频率分布直…

SpringMVC框架

SpringMVC 三层架构MVC模式SpringMVC入门案例总结 三层架构 表现层(web) 页面数据的收集,产出页面 业务逻辑层(service) 业务处理 数据访问层(Dao) 数据持久化 MVC模式 SpringMVC 基于Java…

BOSS直聘上算法岗位的薪资分析

目录 一、数据介绍及预处理 1、数据介绍 2、数据预处理 二、数据分析 1、缺失值统计 2、岗位数量、薪资水平统计 3、企业维度岗位数量 4、top薪资岗位 三、划重点 少走10年弯路 元旦抽空爬取了一下BOSS直聘上base北京的算法岗位的相关数据,本文简单分析拿…

Linux 系统拉取 Github项目

一、安装Git 在Linux上拉取GitHub项目可以使用Git命令。首先确保已经安装了Git。如果没有安装,可以通过包管理器(比如apt、yum)来进行安装。 sudo yum install git #查看安装版本 git -version二、关联GitHub 配置本地账户和邮箱 >>…

HarmonyOS4.0系统性深入开发08服务卡片架构

服务卡片概述 服务卡片(以下简称“卡片”)是一种界面展示形式,可以将应用的重要信息或操作前置到卡片,以达到服务直达、减少体验层级的目的。卡片常用于嵌入到其他应用(当前卡片使用方只支持系统应用,如桌…

《师兄啊师兄》:以“稳健”诠释修仙,反套路喜剧动画赢麻了!

在众多动画题材中,修仙动画一直以其独特的东方神秘色彩和热血的打斗场景深受观众喜爱,可以说是国漫中最具本土特色的题材之一。近年来,大量的修仙题材爆款IP被改编成动画,整体反响非常热烈。动画男主角们通过不断地修炼&#xff0…

深度学习——PIL和OpenCV

PIL 官方文档 格式互转 opencv cv2.imread() 参数: filepath:读入imge的完整路径 flags:标志位,{cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSCALE,cv2.IMREAD_UNCHANGED} cv2.IMREAD_COLOR:默认参数&…

Cypress安装与使用教程(3)—— 软测大玩家

😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。 📡主页地址:【Austin_zhai】 🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。…

计算商场优惠

#include<stdio.h> #include<string.h> #include<math.h> double amount(double list[], int n, double min) {int i;double sum 0, cheap list[0];for (i 0; i < n; i){sum sum list[i];if (list[i] < cheap) //找出最小的cheap list[i];}if (n…

Rust赋值语句和数字类型

赋值语句 在Rust中&#xff0c;使用let关键字定义变量。格式是let 变量名:变量类型 变量值;&#xff0c;下边是个例子&#xff1a; let age:i32 18;这就是定义一个有符号32位的数字变量age&#xff0c;而其中的值是18。 而在C语言定义变量的语句格式是类型 变量名 变量值。…

Tinker 环境下数据表的用法

如果我们要自己手动创建一个模型文件&#xff0c;最简单的方式是通过 make:model 来创建。 php artisan make:model Article 删除模型文件 rm app/Models/Article.php 创建模型的同时顺便创建数据库迁移 php artisan make:model Article -m Eloquent 表命名约定 在该文件中&am…

【软件工程】设计概念

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 软件工程中的设计概念 概念&#xff1a; 结语 我的其他博客 前言 在数字时代的浪潮中&#xff0c;软件工程设计成为塑造创新…

钡铼案例 污水处理远程监控系统的应用介绍

背景 这几年以来&#xff0c;随着国家对环保方面的重视&#xff0c;各地纷纷建立了自己的污水处理站。如何才能保护水资源让其循环利用达到节能减排&#xff0c;是目前急需解决的&#xff0c;正是污水处理项目对水资源的改善以及人民生活水平的提高有着重大的意义。 污水处理…

AC——对HTTPS数据进行行为审计时的解密方式

目录 SSL中间人解密 客户端代理解密&#xff08;准入插件解密&#xff09; 深信服的AC提供两种SSL解密技术用于对https行为进行解密 中间人解密和准入插件解密 SSL中间人解密 解密工作原理 当内网PC端发起SSL连接请求的时候&#xff0c;AC会以代理服务器的身份&#xff0…

vba抓取网页数据

哈喽&#xff0c;哈喽&#xff0c;大家好&#xff01;大家2024发大财啦&#xff01; 不知道&#xff0c;平时大家爱不爱看电影呢&#xff1f;从今年的贺岁档的拍片来看&#xff0c;今年的电影还挺多&#xff0c;而且国产优秀电影居多&#xff0c;元旦假期期间我也去看了部喜剧…

【数据库原理】(4)数据模型介绍

在数据库中&#xff0c;数据不仅包含数据本身的内容&#xff0c;还包括数据之间的关系。这是因为计算机无法直接处理现实世界中的具体事物&#xff0c;因此必须将这些事物抽象成数据模型&#xff0c;以便计算机处理。 数据处理的三个领域 数据从现实世界到数据库里的具体表示…

【C++学习】:命名空间、输入输出和缺省参数全面解析

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; C入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. 命名空间1.1 为什么需要命名空间&#xff1f;1.2 命名空间的定义1.3 命名空间特性1…

3个值得推荐的WPF UI组件库

WPF介绍 WPF 是一个强大的桌面应用程序框架&#xff0c;用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、数据绑定、样式和模板、动画效果等功能&#xff0c;让开发者可以创建出吸引人且交互性强的应用程序。 HandyControl HandyControl是一套WPF控件库&…

图像分割实战-系列教程9:U2NET显著性检测实战1

&#x1f341;&#x1f341;&#x1f341;图像分割实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 U2NET显著性检测实战1 1、任务概述

如何本地快速部署Apache服务器并使用内网穿透工具实现公网访问内网服务

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…