MySQL的InnoDB存储引擎的数据页结构详解

目录
  • 1InnoDB页的概念
  • 2数据页的结构
  • 3记录在页中的存储
  • 4PageDirectory页目录
  • 5FileHeader文件头部
  • 6InnoDB页和记录的关系
  • 7没有索引时查找记录
  • 总结

1 InnoDB页的概念

InnoDB是一个将表中的数据存储在磁盘上的存储引擎,即使我们关闭并重启服务器,数据还是存在。而真正处理数据的过程发生在内存中,所以需要把磁盘中的数据加载到内存中,所以需要把磁盘中的数据加载到内存中。如果处理写入和修改请求,还需要将内存中的内容刷新到磁盘上。而我们知道读写磁盘的速度非常慢,与读写内存差了几个数量级。当我们想从表中获取某些记录时,InnoDB存储引擎需要一条一条的把记录从磁盘上读出来么?不,那样会慢死,InnoDB采取的方式是,将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位。InnoDB中页的大小一般为16KB。也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。

2 数据页的结构

存放表中记录的叫索引页也叫数据页,数据页代表的这块16KB大小的存储空间可以划分为多个部分,不同部分有不同功能。

我们自己存储的记录会按照指定的行格式存储到User Records部分,但是一开始生成页的时候,其实并没有User Records部分,每当插入一条记录时,都会从Free Space部分申请一个记录大小的空间,并将这个空间划分到User Records部分。当Free Records部分的空间全部被User Records部分替代掉之后,也就意味着这个页被用完了,此时如果还有新的记录插入,就需要去申请页了。

3 记录在页中的存储

假如向page_demo表中插入4条记录,那么这4条记录的存储方式为:

insert into page_demo values(1,100,'aaaa'),(2,200,'bbbb'),(3,300,'cccc'),(4,400,'dddd');

无论向页中插入了多少条记录,InnoDB规定,任何用户记录都比infimum记录大,任何用户记录都不supermum小。

通过记录的存储方式可以看到,记录按照主键从小到大的顺序形成了一个单向链表,通过一条记录可以找到它的下一条记录,下一条记录指的并不是插入顺序中的下一条记录,而是按照主键值由小到大的顺序排列的下一条记录,而且规定infimum记录的下一条记录就是本页中主键值最小的用户记录,本页中主键值最大的用户记录的下一条记录就是supermum记录,supermum记录是单向链表中的最后一个节点。

无论怎么对页中的记录进行增删改查操作,InnoDB始终会维护记录的一个单向链表,链表中的各个节点是按照主键值由小到大的顺序链接起来的。

4 Page Directory页目录

我们知道记录页是按照主键值由小到大的顺序串联成了单向链表,如果想根据主键值查找页中的某条记录,该咋办呢?比如下面的查询语句:

select * from page_demo where c1=3;

最笨的方法就是从Infimum记录开始,沿着单向链表一直往后找,而且在找的时候可以投机取巧,因为链表中各个记录的值是按照从小到大的顺序排列的,所以当链表中的某个节点记录的主键值大于想要查找的主键值时,就可以停止查找了。

当页中存储的记录数量比较少时,这种方法用起来没有啥问题,但是,如果一个页中存储了非常多的记录,遍历操作对性能来说还是有损耗的,所以遍历查找是一个笨方法,为此InnoDB设计了Page Directory页目录。

(1) 将所有正常的记录(包括infinmumsupermum记录)划分为几个组。InnoDB对每个分组的条数是有规定的,infimum记录所在的分组只能有一条记录,supermum记录所在的分组拥有的记录数只能在18条之间,剩下的分组中记录的条数范围只能在48之间。

(2) 将每个组中最后一条记录在页面中的地址偏移量单独提取出来按顺序存储到靠近页尾部的地方,这个地方就是Page Directory

比如,现在page_demo有6条记录,InnoDB会把他们分成2个组,第一组只有一个infimum记录,第二组是剩余的5条记录,2个组就对应着两个槽,每个槽存放着每个组中最大的那条记录在页面中的地址偏移量。

由于现在page_demo表中的记录太少,无法掩饰在添加页目录之后是如何加快查找速度的,所以再往page_demo表中添加一些记录。

insert into page_demo
values(1,100,'aaaa'),(2,200,'bbbb'),(3,300,'cccc'),(4,400,'dddd'),(5,500,'eeee'),(6,600,'ffff'),(7,700,'gggg'),(8,800,'hhhh'),(9,900,'iiii'),(10,1000,'jjjj'),(11,1100,'kkkk'),(12,1200,'llll'),(13,1300,'mmmm'),(14,1400,'nnnn'),(15,1500,'oooo'),
(16,1600,'pppp')

现在页中就一共有18条记录了(包括infimum记录和supermum记录),这些记录被分成了5个组,因为各个槽之间是挨着的,而且他们代表的记录的主键值都是从小到大排序的,所以可以使用二分法来快速查找。5个槽的编号跟别为0,1,2,3,4,所以初始情况下最低的槽就是low=0,最高的槽就是high=4,假如我们想要寻找主键值为6的记录,过程就是这样的:

(1) 计算中间槽的位置:(0+4)/2=2,查看槽2对应记录的主键值8;又因为8>6,所以设置high=2,low保持不变。

(2) 重新计算中间槽的位置:(0+2)/2=1,查看槽1对应的记录的主键值为4,又因为4<6,所以设置low=1,high保持不变。

(3) 因为high-low=1,所以主键值为6的记录在槽2对应的组中,此时需要找到槽2所在分组中主键值最小的那条记录,然后沿着单向链表遍历槽2中的记录。

综上所述,在一个数据页中查找指定主键值的记录时,过程分为2步:

(1) 通过二分法确定该记录所在分组对应的槽,然后找到该槽所在分组中主键值最小的那条记录。

(2) 通过记录的next_record属性遍历该槽所在分组中的各个记录。

5 File Header文件头部

InnoDB是以页为单位存放数据的,有时在存放某种类型的数据时,占用的空间非常大。InnoDB可能无法一次性为这么多数据分配一个非常大的存储空间,而如果分散到多个不连续的页中进行存储,则需要把这些也关联起来,FIL_PAGE_PREVFIL_PAGE_NEXT就分别代表本数据页的上一个页和下一个页的页号。这样通过建立一个双向链表就把许许多多的页串联起来了,而无须这些也在物理上真正连着。所以存储记录的数据页其实可以组成一个双向链表。

6 InnoDB页和记录的关系

各个数据页可以组成一个双向链表,而每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表,每个数据页都会为存储在它里面的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的槽,然后遍历该槽对应分组中的记录即可快速找到指定的记录。

7 没有索引时查找记录

1、在一个页中查找:

假设现在表中的记录较少,所有的记录都可以存放在一个页中,在查找记录时,可以根据搜索条件的不同可以分为两种情况:

(1) 以主键为搜索条件:可以在页目录中使用二分法快速定位到指定的槽,然后遍历该槽对应分组中的记录,即可快速定位到指定的记录。

(2) 以其他列作为搜索条件:对于非主键列的查找就没有那么幸运了,因为在数据页中并没有为非主键列建立所谓的页目录,所以无法通过二分法快速定位相应的槽,在这种情况下只能从Infimum记录开始依次遍历单向链表中的每条记录,然后对比每条记录是否符合搜索条件,这种查找的效率非常低。

2、在很多页中查找:

在很多时候,表中存放的记录都是非常多的,需要用到好多的数据页来存储这些记录。在很多页中查找记录可以分为两个步骤:

(1) 定位到记录所在的页;

(2) 从所在的页内查找相应的记录;

在没有索引的情况下,无论是根据主键列还是其他的列进行查找,由于我们不能快速的定位到记录所在的页,所以只能从第一页沿着双向链表一直往下找。在每一页中我们根据上面说的查找方式去查找指定的记录。因为要遍历所有的数据页,所以这种方式显然是超级耗时的。如果一个表有一亿条记录,使用这种方式去查找记录,估计要到猴年马月才能查到结果,所以就需要一种能高效完成搜索的方法,即索引。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 详解MySQL InnoDB存储引擎的内存管理

    存储引擎之内存管理 在InnoDB存储引擎中,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的,即最频繁使用的页在LRU列表的最前段,而最少使用的页在LRU列表的尾端,当缓冲池不能存放新读取到的页时,首先释放LRU列表尾端的页. 上面的图中,我使用8个数据页来表示队列,具体作用,先卖个关子.在InnoDB存储引擎中,缓冲池中页的默认大小是16KB,LRU列表中有一个midpoint的位置,新读取到的数据页并不是直接放入到LRU列表的首部,而是放入

  • 详解MySql中InnoDB存储引擎中的各种锁

    目录 什么是锁 InnoDB存储引擎中的锁 锁的算法 行锁的3种算法 幻像问题 锁的问题 脏读 不可重复读 丢失更新 死锁 什么是锁 现实生活中的锁是为了保护你的私有物品,在数据库中锁是为了解决资源争抢的问题,锁是数据库系统区别于文件系统的一个关键特性.锁机制用于管理对共享资源的并发访. 数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性 InnoDB存储引擎区别于MyISAM的两个重要特征就是:InnoDB存储引擎支持事务和行级别的锁,MyISAM只支持表级别的锁 In

  • MySQL学习(七):Innodb存储引擎索引的实现原理详解

    概述 在数据库当中,索引就跟树的目录一样用来加快数据的查找速度,对于一个SQL查询操作,根据索引快速过滤掉不符合要求的数据并定位到符合要求的数据,从而不需要扫描整个表来获取所需的数据. 在innodb存储引擎中,主要是基于B+树来实现索引,在非叶子节点存放索引关键字,在叶子节点存放数据记录或者主键索引(或者说是聚簇索引)中的主键值,所有的数据记录都在同一层,叶子节点,即数据记录直接之间通过指针相连,构成一个双向链表,从而可以方便地遍历到所有的或者某一范围的数据记录. B树,B+树 B树和B+树都

  • MySQL InnoDB存储引擎的深入探秘

    前言 在MySQL中InnoDB属于存储引擎层,并以插件的形式集成在数据库中.从MySQL5.5.8开始,InnoDB成为其默认的存储引擎.InnoDB存储引擎支持事务.其设计目标主要是面向OLTP的应用,主要特点有:支持事务.行锁设计支持高并发.外键支持.自动崩溃恢复.聚簇索引的方式组织表结构等. 体系架构 InnoDB存储引擎是由内存池.后台线程.磁盘存储三大部分组成. 线程 InnoDB 使用的是多线程模型, 其后台有多个不同的线程负责处理不同的任务 Master Thread Maste

  • 简述MySQL InnoDB存储引擎

    前言: 存储引擎是数据库的核心,对于 MySQL 来说,存储引擎是以插件的形式运行的.虽然 MySQL 支持种类繁多的存储引擎,但最常用的当属 InnoDB 了,本篇文章将主要介绍 InnoDB 存储引擎相关知识. 1. InnoDB 简介 MySQL 5.5 版本以后,默认存储引擎就是 InnoDB 了.InnoDB 是一种兼顾了高可靠性和高性能的通用存储引擎.在 MySQL 5.7 中,除非你配置了其他默认存储引擎,否则执行 CREATE TABLE 不指定 ENGINE 的语句将创建一个

  • Mysql Innodb存储引擎之索引与算法

    目录 一.概述 二.数据结构与算法 1.二分查找 2.二叉查找树和平衡二叉树 1)二叉查找树 2)平衡二叉树 三.B+树 1.B+树完整定义 2.关于 M 和 L的选定案例 四.B+树索引 1.聚集索引 2.辅助索引 五.关于 Cardinality 值 1.Cardinality定义 2.Cardinality的更新 六.B+树索引的使用 1.联合索引 2.覆盖索引 3.优化器选择不使用索引的情况 4.索引提示 5.Multi-Range Read 优化 (MRR) 6.Index Condi

  • MySQL的InnoDB存储引擎的数据页结构详解

    目录 1InnoDB页的概念 2数据页的结构 3记录在页中的存储 4PageDirectory页目录 5FileHeader文件头部 6InnoDB页和记录的关系 7没有索引时查找记录 总结 1 InnoDB页的概念 InnoDB是一个将表中的数据存储在磁盘上的存储引擎,即使我们关闭并重启服务器,数据还是存在.而真正处理数据的过程发生在内存中,所以需要把磁盘中的数据加载到内存中,所以需要把磁盘中的数据加载到内存中.如果处理写入和修改请求,还需要将内存中的内容刷新到磁盘上.而我们知道读写磁盘的速度

  • Mysql InnoDB引擎中的数据页结构详解

    目录 Mysql InnoDB引擎数据页结构 一.页的简介 二.数据页的结构 三.记录在页中的存储结构 四.记录头信息 1. deleted_flag 2. min_rec_flag 3. n_owned 4. heap_no 5. record_type 6. next_record Mysql InnoDB引擎数据页结构 InnoDB 是 mysql 的默认引擎,也是我们最常用的,所以基于 InnoDB,学习页结构.而学习页结构,是为了更好的学习索引. 一.页的简介 页是 InnoDB 管理

  • Innodb存储引擎中的后台线程详解

    目录 1.maste thread 2.IO Thread 3.purge thread 4.page cleaner thread 总结 1.maste thread 负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性. 2.IO Thread 负责IO请求的回调处理. 1.0版本之前有4个IO Thread,负责write.read.insert buffer和log IO Thread 1.0.x开始,read thread和write thread分别增加到4个,不再使用innodb_

  • MySQL中InnoDB存储引擎的锁的基本使用教程

    MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-leve locking)或表级锁,默认为页面锁 InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁 各种锁特点 表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生冲突的概率最高,并发度最低 行级锁:开销大,加锁慢:会出现死锁:锁定粒度最小,发生锁冲突的概率最低,并发度也最高 页面锁:开销和加锁时间介于表锁和行锁之间:会出现死锁:锁定粒度介于表锁和行锁之

  • MySQL Limit性能优化及分页数据性能优化详解

    MySQL Limit可以分段查询数据库数据,主要应用在分页上.虽然现在写的网站数据都是千条级别,一些小的的优化起的作用不大,但是开发就要做到极致,追求完美性能.下面记录一些limit性能优化方法. Limit语法: SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset LIMIT子句可以被用于强制 SELECT 语句返回指定的记录数.LIMIT接受一个或两个数字参数.参数必须是一个整数常量. 如果给定两个参数,第一个参数指定

  • MySql InnoDB存储引擎之Buffer Pool运行原理讲解

    目录 1. 前言 2. Buffer Pool 2.1 Buffer Pool结构 2.2 Free链表 2.3 缓冲页哈希表 2.4 Flush链表 2.5 LRU链表 2.6 多个实例 2.7 Buffer Pool状态信息 3. 总结 1. 前言 我们已经知道,对于InnoDB存储引擎而言,页是磁盘和内存交互的基本单位.哪怕你要读取一条记录,InnoDB也会将整个索引页加载到内存.哪怕你只改了1个字节的数据,该索引页就是脏页了,整个索引页都要刷新到磁盘.InnoDB是基于磁盘的存储引擎,如

  • 聊聊MySQL中的存储引擎

    基础知识 在关系型数据库中每一个数据表相当于一个文件,而不同的存储引擎则会构建出不同的表类型. 存储引擎的作用是规定数据表如何存储数据,如何为存储的数据建立索引以及如何支持更新.查询等技术的实现. 在Oracle以及SqlServer等数据库中只支持一种存储引擎,故其数据存储管理机制都是一样的,而MySQL中提供了多种存储引擎,用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据自己的需要编写自己的存储引擎. 如处理文本文件可使用txt类型,处理图片可使用png类型 存储引擎 在My

  • mysql 体系结构和存储引擎介绍

    目录 1 前言 2 mysql 配置文件加载顺序 3 mysql 引擎介绍 3.1 InnoDB 引擎 3.2 MyISAM 引擎 3.3 NDB 引擎 3.4 Archive 引擎 3.5 Federated 引擎 3.6 Maria 引擎 3.7 其它引擎 4 总结 1 前言 mysql 是一个单进程多线程架构的可移植的数据库,mysql 数据库实例在系统上的表现就是一个进程,可以在所有的平台上运行. mysql 的整体架构图如下图所示:  2 mysql 配置文件加载顺序 mysql 启动

随机推荐