百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

MySQL 的 InnoDB 存储引擎为例讲解,SQL Server、Oracle 的原理

mhr18 2024-10-10 06:44 19 浏览 0 评论

关注私信回复:555领取Java高级架构资料、Spring源码分析、Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式等

InnoDB 引擎数据存储

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

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

这里需要注意的一点是,在某个页内插入新行时,为了减少数据的移动,通常是插入到当前行的后面或者是已删除行留下来的空间,所以在某一个页内的数据并不是完全有序的(后面页结构部分有细讲)。

但是为了数据访问顺序性,在每个记录中都有一个指向下一条记录的指针,以此构成了一条单向有序链表,不过在这里为了方便演示我是按顺序排列的!

由于数据还比较少,一个页就能容下,所以只有一个根结点,主键和数据也都是保存在根结点(左边的数字代表主键,右边名字、性别代表具体的数据)。

假设我们写入 10 条数据之后,Page1 满了,再写入新的数据会怎么存放呢?

我们继续看下图:



有个叫“秦寿生”的朋友来了,但是 Page1 已经放不下数据了,这时候就需要进行页分裂,产生一个新的 Page。

在 InnoDB 中的流程是怎么样的呢?

  • 产生新的 Page2,然后将 Page1 的内容复制到 Page2。
  • 产生新的 Page3,“秦寿生”的数据放入 Page3。
  • 原来的 Page1 依然作为根结点,但是变成了一个不存放数据只存放索引的页,并且有两个子结点 Page2、Page3。

这里有两个问题需要注意的是:

①为什么要复制 Page1 为 Page2 而不是创建一个新的页作为根结点,这样就少了一步复制的开销了?

如果是重新创建根结点,那根结点存储的物理地址可能经常会变,不利于查找。

并且在 InnoDB 中根结点是会预读到内存中的,所以结点的物理地址固定会比较好!

②原来 Page1 有 10 条数据,在插入第 11 条数据的时候进行裂变,根据前面对 B-Tree、B+Tree 特性的了解,那这至少是一棵 11 阶的树,裂变之后每个结点的元素至少为 11/2=5 个。

那是不是应该页裂变之后主键 1-5 的数据还是在原来的页,主键 6-11 的数据会放到新的页,根结点存放主键 6?

如果是这样的话,新的页空间利用率只有 50%,并且会导致更为频繁的页分裂。

所以 InnoDB 对这一点做了优化,新的数据放入新创建的页,不移动原有页面的任何记录。

随着数据的不断写入,这棵树也逐渐枝繁叶茂,如下图:



每次新增数据,都是将一个页写满,然后新创建一个页继续写,这里其实是有个隐含条件的,那就是主键自增!

主键自增写入时新插入的数据不会影响到原有页,插入效率高!且页的利用率高!

但是如果主键是无序的或者随机的,那每次的插入可能会导致原有页频繁的分裂,影响插入效率!降低页的利用率!这也是为什么在 InnoDB 中建议设置主键自增的原因!

这棵树的非叶子结点上存的都是主键,那如果一个表没有主键会怎么样?在 InnoDB 中,如果一个表没有主键,那默认会找建了唯一索引的列,如果也没有,则会生成一个隐形的字段作为主键!

有数据插入那就有删除,如果这个用户表频繁的插入和删除,那会导致数据页产生碎片,页的空间利用率低,还会导致树变的“虚高”,降低查询效率!这可以通过索引重建来消除碎片提高查询效率!

InnoDB 引擎数据查找

数据插入了怎么查找呢?

  • **找到数据所在的页。**这个查找过程就跟前面说到的 B+Tree 的搜索过程是一样的,从根结点开始查找一直到叶子结点。
  • **在页内找具体的数据。**读取第 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 的记录时,先通过二分法在稀疏索引中找到对应的槽,也就是 Page Directory 中“8”这个槽。

“8”这个槽指向的是该数据块中最大的记录,而数据是单向链表结构,所以无法逆向查找。

所以需要找到上一个槽即“4”这个槽,然后通过“4”这个槽中最大的用户记录的指针沿着链表顺序查找到目标记录。

聚集索引&非聚集索引

前面关于数据存储的都是演示的聚集索引的实现,如果上面的用户表需要以“用户名字”建立一个非聚集索引,是怎么实现的呢?

我们看下图:



非聚集索引的存储结构与前面是一样的,不同的是在叶子结点的数据部分存的不再是具体的数据,而是数据的聚集索引的 Key。

所以通过非聚集索引查找的过程是先找到该索引 Key 对应的聚集索引的 Key,然后再拿聚集索引的 Key 到主键索引树上查找对应的数据,这个过程称为回表!

PS:图中的这些名字均来源于网络,希望没有误伤正在看这篇文章的你~^_^

InnoDB 与 MyISAM 引擎对比

上面包括存储和搜索都是拿的 InnoDB 引擎为例,那 MyISAM 与 InnoDB 在存储上有啥不同呢?憋缩话,看图:



上图为 MyISAM 主键索引的存储结构,我们能看到的不同是:

  • 主键索引树的叶子结点的数据区域没有存放实际的数据,存放的是数据记录的地址。
  • 数据的存储不是按主键顺序存放的,是按写入的顺序存放。

也就是说 InnoDB 引擎数据在物理上是按主键顺序存放,而 MyISAM 引擎数据在物理上按插入的顺序存放。

并且 MyISAM 的叶子结点不存放数据,所以非聚集索引的存储结构与聚集索引类似,在使用非聚集索引查找数据的时候通过非聚集索引树就能直接找到数据的地址了,不需要回表,这比 InnoDB 的搜索效率会更高呢!

索引优化建议

大家经常会在很多的文章或书中能看到一些索引的使用建议,比如说:

  • like 的模糊查询以 % 开头,会导致索引失效。
  • 一个表建的索引尽量不要超过 5 个。
  • 尽量使用覆盖索引。
  • 尽量不要在重复数据多的列上建索引。

为了感谢你的关注,送你一份我精心准备的资料。私信回复:555领取

相关推荐

SQL入门知识篇(sql入门新手教程视频)

一、什么是数据库?什么是SQL?1、数据库:存放数据,可以很多人一起使用2、关系数据库:多张表+各表之间的关系3、一张表需要包含列、列名、行4、主键:一列(或一组列),其值能够唯一区分表中的每个行。5...

postgresql实现跨库查询-dblink的妙用

技术导语:用惯了oracle的dblink,转战postgresql,会一时摸不着头脑。本期就重点详细讲解postgresql如何安装dblink模块及如何使用dblink实现跨库查询。安装cont...

Oracle VM VirtualBox虚拟机软件(oracle vm virtualbox win10)

OracleVMVirtualBox是一款完全免费的虚拟机软件,下载银行有提供下载,软件支持安装windows、linux等多个操作系统,让用户可以在一台设备上实现多个操作系统的操作。同时软件有着...

开源 SPL 轻松应对 T+0(开源srs)

T+0问题T+0查询是指实时数据查询,数据查询统计时将涉及到最新产生的数据。在数据量不大时,T+0很容易完成,直接基于生产数据库查询就可以了。但是,当数据量积累到一定程度时,在生产库中进行大数据...

中小企业佳选正睿ZI1TS4-4536服务器评测

随着科技的不断发展,各行各业对于数据使用越加频繁,同时针对服务器的选择方面也就越来越多样化和细分化。那么对于我们用户来说,如何选择符合自身业务需求和最优性价比的产品呢?笔者将通过刚刚购买的这台服务器的...

MFC转QT:Qt基础知识(mfc和qt的区别)

1.Qt框架概述Qt的历史和版本Qt是一个跨平台的C++应用程序开发框架,由挪威公司Trolltech(现为QtCompany)于1991年创建。Qt的发展历程:1991年:Qt项目启动1995年...

数据库,QSqlTableModel(数据库有哪些)

QMYSQL——mysqlQSQLITE——sqliteQOICQ——orcale所需头文件.pro增加sql#include<QSqlDatabase>#include<Q...

python通过oledb连接dbf数据库(python连接jdbc)

起因:因为工作需要,需要读取dbf文件和系统数据中数据进行校对,因为知道dbf文件可以用sql查询,所以想能不能像mysql/oracle那样连接,再调用执行sql方法,通过一系列百度,尝试,最终通过...

Excel常用技能分享与探讨(5-宏与VBA简介 VBA与数据库)

在VBA(VisualBasicforApplications)中使用数据库(如Access、SQLServer、MySQL等)具有以下优点,适用于需要高效数据管理和复杂业务逻辑的场景:1....

Excel常用技能分享与探讨(5-宏与VBA简介 VBA与数据库-二)

以下是常见数据库软件的详细配置步骤,涵盖安装、驱动配置、服务启动及基本设置,确保VBA能够顺利连接:一、MicrosoftAccess适用场景:小型本地数据库,无需独立服务。配置步骤:安装Acces...

Windows Docker 安装(docker安装windows容器)

Docker并非是一个通用的容器工具,它依赖于已存在并运行的Linux内核环境。Docker实质上是在已经运行的Linux下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的L...

Windows下安装Ubuntu虚拟机方法(windows下安装ubuntu20)

在Windows下安装Ubuntu虚拟机。选择使OracleVMVirtualBox安装Ubuntu虚拟机。1.下载和安装OracleVMVirtualBox:访问OracleVMVir...

java入门教程1 - 安装和配置(win和linux)

windows安装和配置安装javahttps://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html目前大部分项目的...

Centos7 安装Tomcat8服务及配置jdk1.8教程

1、下载jdk1.8压缩包下载地址:https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.htmltom...

全网最完整的免费java教程讲义(一)——java配置和安装

一,安装Java1)安装JDK要学习和使用java,首先需要安装JDK(JavaDevelopemntKit),相当于java安装包。Java的下载页在甲骨文官网上:https://www.or...

取消回复欢迎 发表评论: