mysql InnoDB 数据存储和查找

2023-11-18

InnoDB 引擎数据存储

要想了解数据库 InnoDB 引擎是怎么样存储数据的,必须先了解 B+Tree,了解之后才容易理解其存储原理

在 InnoDB 存储引擎中,也有页的概念,默认每个页的大小为 16K,也就是每次读取数据时都是读取 4*4K 的大小。

一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为 10^3)。也就是说一个深度为3的B+Tree索引可以维护10^3 * 10^3 * 10^3 = 10亿 条记录。

实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在2~4层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作

假设我们现在有一个用户表,我们往里面写数据,如下图:

注意:在某个页内插入新数据时,为了减少数据的移动,通常是插入到当前行的后面或者是已删除行留下来的空间,所以在某一个页内的数据并不是完全有序的。为了数据访问的顺序性,每条记录中都有指向下一条记录的指针,以此构成了一个有序的链表

由于只有10条记录,可以放在同一页 page1上,如果每页只能存放10条记录,当第 11 条记录插入时,数据是怎么存放的呢?如下图:

存储过程如下:

1、创建新页 page2,将 page1 的数据复制到 page2上

2、创建新页 page3,将新数据插入到 page3中

3、原来的 page1 还作为根节点,但是变成了一个只存放索引(11)不存放数据的页了,它有两个子节点 page2 和 page3

这里有以下两个问题

1、为什么要复制 page1 数据到 page2 而不是创建一个新的 page1 作为根节点 ,原来的 page1 成为 page2,这样子就减少了数据复制开销?

如果是创建新的 page1 为根节点的话,其存储的物理地址可能会变,在 InnoDB 引擎中根结点是会预读到内存中的,如果根节点的地址变了,不利于数据查找了

2、插入第 11 条数据之后,节点裂变了,根据 B+Tree 的特性,它至少是 11 阶,而裂变之后每个节点的元素至少为 11/2 = 5个,那么数据分布应该是 1-5 key的数据放到 page2 中,6-11 key的数据放到 page3 中,根节点存放主键 key 6呢?

如果是这样的话,新页的利用率只有 50%,而且还会导致频繁的页(节点)分裂

由于这个缺点,InnoDB 对这一点做了优化,新插入的数据放到新创建的页,原有页的数据不移动

随着数据的不断写入,B+Tree数据存储如下图:

 

 


主键自增

每当数据页写满之后就会创建新的页来存储,这里其实有个隐含条件,那就是主键自增。

主键自增优势:插入效率高,页的利用率高

主键自增时新插入的数据不会影响到原有页的数据,不仅插入效率高,而且页的利用率也高。如果主键无序或者随机,每次插入数据可能会导致原有页频繁分裂,严重影响插入效率,同时页的利用率也比较低。这也是为什么在 InnoDB 中建议设置主键自增的原因

B+Tree 非叶子节点存放的都是主键索引,如果一个表中没有设置主键会怎么处理呢?

如果一个表中没有设置主键,默认会找一个建了唯一索引的列。如果唯一索引列也没有,则会生成一个隐形的字段作为主键

如果表频繁的插入和删除的话,会导致页产生碎片,降低页的空间利用率,即降低查询效率,这可以通过索引重建来消除碎片,提高查询效率

InnoDB 引擎数据查找

通常在B+Tree上有两个头指针,一个指向根节点,另一个指向 key(关键字)最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找

InnoDB 存储数据后,怎么做查找的呢?通过以下两个步骤查找

1、找到数据所在的页,这个过程就是 B+Tree 查找,即从根节点开始一直找到叶子节点(数据所在页)

2、在数据页内查找数据,读取 1 中查找到的叶子节点数据(页数据)到内存中,然后通过分块查找的方法找到具体数据

这个查找过程就像是到新华字典上查找某一个汉字,先定位到哪一页,然后在页中找到具体的汉字。

InnoDB 在页中使用了哪种策略快速查找某个主键呢?这就要我们从页结构了解开始,如下图:

左边区域:左边蓝色区域称为 Page Directory(页目录),这块区域由多个 Slot 组成,是一个稀疏索引结构,即一个槽中可能属于多个记录,最少属于 4 条记录,最多属于 8 条记录。槽内的数据是有序存放的,所以当我们寻找一条数据的时候可以先在槽中通过二分法查找到一个大致的位置

右边区域:数据区域,每一个数据页中都包含多条行数据。注意看图中最上面和最下面的两条特殊的行记录 Infimum 和 Supremum,这是两个虚拟的行记录。在没有其他用户数据的时候 Infimum 的下一条记录的指针指向 Supremum。当有用户数据的时候,Infimum 的下一条记录的指针指向当前页中最小的用户记录当前页中最大的用户记录的下一条记录的指针指向 Supremum,至此整个页内的所有行记录形成一个单向链表

行记录(右边数据区)被 Page Directory 逻辑的分成了多个块,块与块之间是有序的,也就是说“4”这个槽指向的数据块内最大的行记录的主键都要比“8”这个槽指向的数据块内最小的行记录的主键要小。但是块内部的行记录不一定有序。每个行记录的都有一个 n_owned 的区域(图中粉红色区域),n_owned 标识这个块有多少条数据。伪记录 Infimum 的 n_owned 值总是 1,记录 Supremum 的 n_owned 的取值范围为[1,8],其他用户记录 n_owned 的取值范围[4,8]。并且只有每个块中最大的那条记录的 n_owned 才会有值,其他的用户记录的 n_owned 为 0。

因此当我们要找主键为 6 的记录时,分为下面的步骤:

1、先通过二分法在稀疏索引(左边页目录)中找到对应的槽,也就是 Page Directory 中“8”这个槽。“8”这个槽指向的是该数据块中最大的记录,而数据是单向链表结构,所以无法逆向查找。

2、由于8 槽无法找到数据,则只能找到上一个槽即“4”这个槽,然后通过“4”这个槽中最大的用户记录的指针沿着链表顺序查找到目标记录

聚集索引和辅助索引(非聚集索引)

数据库中的B+Tree索引可以分为聚集索引(clustered index)辅助索引(也称非聚集索引,secondary index)

聚集索引:上面的InnoDB 引擎数据存储中的示例图在数据库中的实现即为聚集索引,聚集索引的 B+Tree 中的叶子节点存放的是整张表的行记录数据

辅助索引(非聚集索引):辅助索引的 B+Tree 中的叶子节点存放的是表的行数据的聚集索引键(key),即主键,和聚集索引不同的是它不存放行记录的全部数据

如果上面的用户表需要以“用户名字”建立一个辅助索引,是怎么实现的呢?辅助索引树如下图:


从上图可以看出,非叶子节点中存放的全部是辅助索引(用户名字),而叶子节点存放的则是辅助索引(用户名字)+ 主键 key

因此当我们使用辅助索引查找数据时,先通过辅助索引在辅助索引树中找到辅助索引对应的主键 key(聚集索引键),然后在用主键 key 到聚集索引树上查找对应的数据,这个过程称为回表。

InnoDB 与 MyISAM 引擎对比

InnoDB 与 MyISAM 引擎在存储数据和查找数据方面有什么不同呢?下面通过一张图来简单了解一下二者区别,MyISAM 聚集索引的存储结构如下图:

从上图可以看出,MyISAM 和 InnoDB 的不同主要体现在两个方面:

1、MyISAM 的 B+Tree 叶子节点数据区存放的不是数据,而是数据记录对应的地址

2、数据的存储不是按照主键顺序存放的,而是按照写入顺序存储的

结论:InnoDB 引擎数据在物理上是按主键 key 顺序存放,而 MyISAM 引擎数据在物理上按插入的顺序存放

由于MyISAM 的叶子结点不存放具体数据,因此辅助索引的存储结构与聚集索引类似,在使用辅助索引查找数据的时候通过辅助索引树就能直接找到数据的地址了,不需要回表,这比 InnoDB 的查找效率高呢

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mysql InnoDB 数据存储和查找 的相关文章

  • 在一个后台为MYSQL的网站上集成搜索

    我有一个位置搜索website http www jammulinks com对于一个城市 我们首先收集该城市所有可能类别的数据 如学校 学院 百货商店等 并将其信息存储在单独的表中 因为每个条目除了名称 地址和电话号码外都有不同的详细信息
  • 加载数据infile,Windows和Linux的区别

    我有一个需要导入到 MySQL 表的文件 这是我的命令 LOAD DATA LOCAL INFILE C test csv INTO TABLE logs fields terminated by LINES terminated BY n
  • MySQL - 多个结果集

    我正在使用 NET Connector 连接到 MySQL 在我的应用程序中 很少有线程使用相同的连接 因此如果 MySQLDataReader 尚未关闭并且某个线程正在尝试执行查询 则会出现该错误 已经有一个打开的 DataReader
  • 在MySQL中生成随机字符串

    我正在尝试使用函数在 phpmyadmin 中获取随机字符串 我有以下代码 CREATE FUNCTION randomPassword RETURNS varchar 128 BEGIN SET chars ABCDEFGHIJKLMNO
  • AWS RDS MySql - 如何在设置“公开可用”后允许访问

    刚刚使用默认设置和用户 密码创建了新的 AWS RDS MySql 实例 我也将其设置为publicly available并在此过程中创建新的 VPC 目前无法从我的笔记本电脑连接到此 RDS mysql h endpoint u myu
  • MySQL 可选的带有 MATCH 的 LEFT JOIN

    我有以下查询 它对 MySQL Innodb 数据库中同一搜索词的两个不同表中的两列执行全文搜索 SELECT Id MATCH tb1 comment tb2 comment AGAINST search term IN BOOLEAN
  • WHERE NOT EXIST 附近的语法错误

    我在堆栈中搜索 但没有一个达到最终答案 我的查询是这样的 INSERT INTO user username frequence autoSend VALUES feri2 3 1 WHERE NOT EXISTS SELECT FROM
  • 更改mysql数据库表中的日期格式

    大家早上好 只是一个简单的问题 在我现有的 MySql 数据库中 我几乎没有包含日期 的列 目前这些是年 月 日格式 但现在我需要将其全部更改为年 月 日格式 我试过了select date format curdate d m Y 但它不
  • 如何在查询语句之外从mysql查询中获取值?

    这是下面的函数console log function quo value value connection query SELECT role from roles where id 1 function error results fi
  • 连接到 OpenShift (Redhat Paas) mysql 实例

    我正在尝试将我的 C 应用程序与 openshift 数据库连接 但我得到了这个例外conn Open Eccezione gt MySql Data MySqlClient MySqlException 0x80004005 Unable
  • Tomcat 6找不到mysql驱动

    这里有一个类似的问题 但关于类路径 ClassNotFoundException com mysql jdbc Driver https stackoverflow com questions 1585811 classnotfoundex
  • 休眠以持久保存日期

    有没有办法告诉 Hibernate java util Date 应该持久保存 我需要这个来解决 MySQL 中缺少的毫秒分辨率问题 您能想到这种方法有什么缺点吗 您可以自己创建字段long 或者使用自定义的UserType 实施后User
  • rake db 问题:迁移 -

    我无法为 Ruby on Rails 设置 MySQL 数据库 设置数据库并确保 config database yml 文件匹配后 我遇到了以下错误消息 U Rails alpha gt rake db migrate trace in
  • 防止 Propel 插入空字符串

    当未设置列时 如何防止 Propel ORM 插入空字符串 CREATE TABLE user uid INTEGER PRIMARY KEY AUTO INCREMENT email VARCHAR 255 NOT NULL UNIQUE
  • 如何对 SQL 进行多次查询

    我正在尝试创建一个表 并在 PHP 脚本的帮助下在数据库中插入一些值 虽然只插入 1 行 但效果很好 当我尝试输入更多行数时 出现错误 我需要为每个查询编写完整的插入语句 因为我正在使用在线 Excel 到 SQL 查询转换器
  • MySQL InnoDB 约束不起作用

    我偶然发现 innoDB 约束的奇怪行为 但找不到原因 我有包含数据的表格 下面列出了它们的结构 CREATE TABLE contents id int 10 unsigned NOT NULL AUTO INCREMENT title
  • Google Cloud SQL 上的故障转移如何运作?

    我打算将 PHP 应用程序 从 Google Cloud Platform 外部的服务器 连接到 Google Cloud SQL 我想知道如何设计应用程序以正确地对其数据库进行故障转移 根据manual https cloud googl
  • 来自数据库的 jfreechart 散点图

    如何使用java中的jfreechart绘制mysql数据库表中数据的散点图 我使用过 Swing 库 任何链接都会有帮助 我搜索了谷歌但找不到理解的解决方案 如果您有代码 请提供给我 实际上我确实做了条形图并使用 jfreechart 绘
  • 重写 URL,将 ID 替换为查询字符串中的标题

    我对 mod rewrite 很陌生 但我做了一些搜索 但找不到这个问题的答案 我有一个网站 它只有一个 PHP 页面 根据查询字符串中传递给它的 ID 提供数十页内容 我想重写 URL 以便此 ID消失并替换为从数据库中提取的页面标题 例
  • 研究MySQL、SQLite源码了解RDBMS实现[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我知道实现数据库是一个很大的话题 但我想通过研究数据库系统的源代码来基本了解数据库系统的工作原理 例如

随机推荐

  • STM32 printf函数无法使用

    要想STM32使用printf函数打印 需要三个条件 条件1 魔术棒配置 条件2 有以下函数 重定向c库函数printf到串口DEBUG USART 重定向后可使用printf函数 int fputc int ch FILE f 发送一个字
  • Java 8:让你的代码更简洁、高效和灵活的新特性

    Java 8 企业中使用最普遍的版本 那么了解它的新特性是非常有必要的 目录 一 函数式接口 二 Lamdba表达式 三 方法引用 四 Stream API 3 1 创建 方法一 通过集合 方法二 通过数组 方法三 通过Stream的of
  • 零知识证明

    一 概念 证明者能够在不向验证者提供任何有用的信息的情况下 使验证者相信某个论断是正确的 零知识证明 Zero Knowledge Proof 起源于最小泄露证明 设P表示掌握某些信息 并希望证实这一事实的实体 设V是证明这一事实的实体 假
  • 前端例程20220728:点击涟漪效果按钮

    演示 原理 监听按钮点击事件 点击事件中获取点击位置 在点击位置生成一个元素作为水波 水波生成后通过扩散同时变透明 水波根据动画时间变透明后销毁 代码
  • 使用Kotlin 重写毕设项目

    Kotlin目前已经转正 成为 Android 开发一级语言 前段时间不忙 将毕业设计用Kotlin 进行重写 毕业设计 Java 版 https blog csdn net qq 29375837 article details 8265
  • 谁能看懂这幅图?

    谁能看懂这幅图
  • 基于MediaPlayer实现视频播放

    一 概述 一个简单的视频播放器 满足一般的需求 使用原生的 MediaPlayer 和 TextureView来实现 功能点 获取视频的首帧进行展示 网络视频的首帧会缓存 视频播放 本地视频或者网络视频 感知生命周期 页面不可见自动暂停播放
  • 51单片机入门——矩阵键盘(附51代码)

    1 硬件介绍 矩阵键盘电路图 硬件如图非常简单 将一个4 4的矩阵键盘的8个管脚引到端子上 在连接到8个I O口上 ARRAY H代表着行 ARRAY L代表着列 当行与列的电平都置低的时候 就选中的相应的矩阵按键 比如当s1按下时 ARR
  • Shell if 条件判断

    Shell 语言中的if条件 一 if的基本语法 if command then 符合该条件执行的语句 elif command then 符合该条件执行的语句 else 符合该条件执行的语句 fi 二 文件 文件夹 目录 判断 b FIL
  • Android系统换字体不root,安卓手机更换字体简易方法(免ROOT)

    很多童鞋都是玩机族 都喜欢diy自己的手机来追求个性 更换手机字体是大家都热衷做的事 但至于换字体的方法 很多童鞋是折腾半天都不明觉厉 有的同学利用高深的方法 先root获取手机权限啊 改系统文件啊 改这改那的终于换了字体 但有时候一重启
  • 【机器学习】6:K-近邻(KNN)算法实现手写数字识别的三种方法

    前言 本来觉得自己从数据建模转人工智能方向应该问题不大 自我感觉自己算法学的不错 结果一个K 邻近实现手写数字识别的代码就让我改了三四天 虽然网上这方面的代码是很多 但是我运行了好几个 结果都不是很理想 一次偶然的念想 为什么我不把这些代码
  • HttpRunner 的中文使用手册

    2018开工大吉 给大家送上 HttpRunner 的中文使用手册 http cn httprunner org
  • 手机端使用ghelper_Anki手机端使用指南(一)

    本篇会对如何使用手机端anki进行详解 有小伙伴询问在应用商店搜索anki找不到名字叫 anki 的软件 这里解释一下 在手机端的名字和电脑端的名字不太一样 安卓对应的名字叫做AnkiDroid IOS对应的名字叫做Ankimobile 不
  • 快速排序法

    partition函数 int partition vector
  • C++ 数学与算法系列之牛顿、二分迭代法求解非线性方程

    1 前言 前文介绍了如何使用 高斯消元法 求解线性方程组 本文秉承有始有终的态度 继续介绍 非线性方程 的求解算法 本文将介绍 2 个非线性方程算法 牛顿迭代法 二分迭代法 牛顿迭代法 Newton s method 又称为牛顿 拉夫逊方法
  • 安装python包的方式,控制台方式以numpy安装为例

    说明 方式1 直接打开cmd 需要配置python环境 控制台输入 python m pip install package name 版本号 方式2 去网上将所需的包下载下来 链接 官方下载链接 一般是 whl格式 然后将其放在自己的路径
  • 【桥接模式】VMware虚拟机配置桥接模式

    在虚拟机配置中 桥接模式和NAT模式是两种常见的网络连接方式 区别 1 桥接模式使虚拟机直接连接到物理网络 可以与外部设备直接通信 并获取唯一IP地址 2 NAT模式使用网络地址转换器将虚拟机的网络流量转发到物理网络上 虚拟机可以与外部网络
  • 强化学习读书笔记

    强化学习读书笔记 09 on policy预测的近似方法 参照 Reinforcement Learning An Introduction Richard S Sutton and Andrew G Barto c 2014 2015 2
  • 理解区块链

    本文基本上是收集的内容汇总 略微全面一点 1 区块链的诞生 互联网上的贸易 几乎都需要借助可资信赖的第三方信用机构来处理电子支付信息 这类系统仍然内生性地受制于 基于信用的模式 区块链技术是构建比特币区块链网络与交易信息加密传输的基础技术
  • mysql InnoDB 数据存储和查找

    InnoDB 引擎数据存储 要想了解数据库 InnoDB 引擎是怎么样存储数据的 必须先了解 B Tree 了解之后才容易理解其存储原理 在 InnoDB 存储引擎中 也有页的概念 默认每个页的大小为 16K 也就是每次读取数据时都是读取