当前位置: 首页 > news >正文

MySQL——学习InnoDB(1)

MySQL——学习InnoDB(1)

文章目录

  • MySQL——学习InnoDB(1)
    • 1. InnoDB的前世今生
      • 1.1 诞生发展
      • 1.2 核心设计
      • 1.3 关键进化
    • 2. InnoDB和MyISAM在性能和安全上的区别
      • 2.1 性能对比
      • 2.2 安全对比
    • 3. InnoDB架构图(内存结构+磁盘结构)
      • 3.1 为什么要设计成内存结构和磁盘结构两个部分?
    • 4. InnoDB的磁盘结构
      • 4.1 表空间是什么
        • 4.1.1 表空间和表空间文件的关系
      • 4.2 用户数据在表空间中如何存储
        • 4.2.1 小区例子
      • 4.3 为什么要使用页这个管理单元
        • 4.3.1 为什么默认是16KB(接水例子)
        • 4.3.2 页默认16KB不会产生浪费吗
      • 4.4 数据页的基本特性
        • 4.4.1 页的物理属性
        • 4.4.2 页的逻辑结构
        • 4.4.3 核心组成部分详解
          • 1. File Header(文件头)
          • 2. Page Header(页头)
          • 3. Infimum + Supremum Records
          • 4. User Records(用户记录)
          • 5. Page Directory(页目录)
          • 6. File Trailer(文件尾)
        • 4.4.4 页的运行时行为
          • 1. 记录插入流程
          • 2. 空间回收
          • 3. 页分裂阈值
        • 4.4.5 页类型扩展
        • 4.4.6 性能优化建议
      • 4.5 大范围查询优化:区(Extent)与顺序I/O
        • 4.5.1 核心问题:随机I/O的性能瓶颈
        • 4.5.2 InnoDB的解决方案:区(Extent)
          • 1. 区的定义
          • 2. 区如何提升性能
        • 4.5.3 关键优化机制
          • 1. 预读(Read-Ahead)
          • 2. 区组(Extent Group)
        • 4.5.4 区如何管理页
      • 4.6 段的作用
        • 4.6.1 核心定位
        • 4.6.2 分类与功能
        • 4.6.3 段的空间管理机制
          • 1. 分配策略对比
          • 2. 碎片区(Fragmented Extent)的特殊性
          • 3. 段与区的映射关系
    • 5. 页的结构
      • 5.1 页大小设置
      • 5.2 页的分类
      • 5.3 页头/页尾结构
        • 5.3.1 ⻚头 - File Header
        • 5.3.2 ⻚尾 - File Trailer
      • 5.4 页主体结构
        • 5.4.1 数据行格式(重点)
          • 1. 变长字段长度列表
          • 2. NULL标记位
          • 3. 头信息(40BIT)
          • 4. 主键值、事务ID、回滚指针
        • 5.4.2 首尾记录标识
        • 5.4.3 页目录查询
      • 5.5 事务信息存储
    • 6. 行结构
      • 6.1 行格式对比
        • 6.1.1 查看行格式
        • 6.1.2 指定行格式
        • 6.1.3 DYNAMIC行特性
        • 6.1.4 变长字段存储
        • 6.1.5 溢出指针结构
        • 6.1.6 格式差异对比
      • 附录:InnoDB存储全景图

1. InnoDB的前世今生

InnoDB做为MySQL的默认存储引擎,其实并不是MySQL开发的,⽽是由 Innobase Oy 公司所开发,2006年五⽉时由甲⻣⽂公司并购。这也是MySQL做为⼀个开源数据库的好处之⼀,第三⽅开发者可以根据⾃⼰的业务场景开发出⾼性能的存储引擎,像 Innobase Oy 公司开发的InnoDB,⼀旦被官⽅采纳,那么就可能通过被收购从⽽得到可观的收⼊,官⽅的产品也得到了有效的扩展,是⼀个双赢的结果。

1.1 诞生发展

  • 2001年:Heikki Tuuri开发,首个支持ACID的MySQL引擎
  • 2005年:被Oracle收购
  • 2010年:成为MySQL 5.5默认引擎
  • 2018年:MySQL 8.0实现原子DDL

1.2 核心设计

  1. 事务引擎
    • MVCC多版本控制
    • 行锁+间隙锁
    • Redo/Undo日志
  2. 存储结构
    • 聚簇索引组织
    • 16KB页存储
    • B+树索引

1.3 关键进化

版本重大改进
5.5默认引擎,缓冲池优化
5.7全文索引,GIS支持
8.0原子DDL,哈希索引

2. InnoDB和MyISAM在性能和安全上的区别

2.1 性能对比

维度InnoDBMyISAM
读写速度写入稍慢(需维护事务日志)读操作更快(无事务开销)
并发能力高并发优(行级锁+MVCC)低并发(表锁,读写阻塞)
索引效率聚簇索引,主键查询极快非聚簇索引,索引/数据分离
缓存机制缓存数据和索引(Buffer Pool)仅缓存索引(Key Buffer)
全表扫描较慢(需处理事务结构)更快(简单数据存储格式)

2.2 安全对比

维度InnoDBMyISAM
崩溃恢复✅ 自动恢复(Redo Log)❌ 需手动修复(REPAIR TABLE
事务支持✅ 完整ACID❌ 不支持
外键约束✅ 支持❌ 不支持
数据一致性✅ 行级锁+MVCC❌ 表锁易丢失更新
日志保护✅ Redo/Undo Log❌ 仅错误日志

3. InnoDB架构图(内存结构+磁盘结构)

内存结构:

  • Buffer Poll
  • Change Buffer
  • Log Buffer
  • 自适应哈希

磁盘结构:

  • 系统表空间
  • 独立表空间
  • 通用表空间
  • 临时表空间
  • 撤销表空间
  • Undo Log
  • 双写缓冲区

在这里插入图片描述

3.1 为什么要设计成内存结构和磁盘结构两个部分?

我们从MySQL实现的⻆度来思考这个问题,数据库的作⽤就是保存数据,⽤⼾的真实数据最终都会保存在磁盘上,在查询数据的过程中,如果每次都从磁盘上读取会严重影响效率,为了提⾼数据的访问效率,InnoDB会把查询到的数据缓存到内存中,当再次查询时,如果⽬标数据已经存在于内存中,就可以从内存中直接读取,从⽽⼤幅提升效率。也就是说磁盘结构中的⽂件是⽤来保存数据实现数据持久化的,内存结构是⽤来缓存数据提升效率的。

4. InnoDB的磁盘结构

4.1 表空间是什么

表空间⽂件是⽤来存储表中数据的⽂件,表空间⽂件的⼤⼩由存储的数据多少决定,不同的表空间⽂件存储数据的种类也有所不同,在MySQL中表空间分为五类,包括:系统表空间、独⽴表空间、通⽤表空间、临时表空间和撤销表空间,这些在上⾯的InnoDB架构图中都有体现。

当使⽤InnoDB存储引擎创建⼀个表时,默认会在数据⽬录对应的数据库⼦⽬录中⽣成相应的表空间⽂件,以 .ibd 为⽂件的后缀,⽤来存储数据和索引,如果每个表都对应⼀个表空间⽂件,称为独⽴表空间,在MySQL5.7及以后的版本中默认为每个表⽣成独⽴表空间,可以通过系统变量innodb_file_per_table[=ON|OFF] 进⾏控制,如果关闭这个选项,则所有表的数据都在系统表空间中存储,独⽴表空间⽂件如下所⽰:

root@turuichen-VMware-Virtual-Platform:/var/lib/mysql/oj# ll # 列出指定数据库⽬录下的所有⽂件
total 764
drwxr-x— 2 mysql mysql 4096 3月 28 17:58 ./
drwx------ 11 mysql mysql 4096 4月 14 17:49 …/
-rw-r----- 1 mysql mysql 131072 4月 6 00:06 oj_questions.ibd # .ibd⽂件是使⽤InnoDB存储引擎创建的表对应的表空间⽂件
-rw-r----- 1 mysql mysql 147456 3月 28 19:50 question_list_info.ibd
-rw-r----- 1 mysql mysql 180224 3月 29 00:14 question_lists.ibd
-rw-r----- 1 mysql mysql 163840 4月 11 00:28 submit_records.ibd
-rw-r----- 1 mysql mysql 147456 3月 27 08:57 users.ibd

4.1.1 表空间和表空间文件的关系

表空间可以理解为MYSQL为了管理数据⽽设计的⼀种数据结构,主要描述的对结构的定义,表空间⽂件是对定义的具体实现,以⽂件的形式存在于磁盘上。

4.2 用户数据在表空间中如何存储

  • ⾸先明确⼀点,⽤⼾的数据以数据⾏的⽅式存储在对应的表空间⽂件中,那么表空间中很多个数据⾏就需要进⾏管理,以便后续进⾏⾼效的查询;

  • 为了⽅便管理,表空间由段 (segment)、区组(group)、区 (extent)、⻚ (page) 、数据⾏组成,其中⻚是 InnoDB 磁盘管理的最⼩单位;

可以这么理解,若⼲数据⾏组成了⻚,多个⻚组成了区,多区组成了区组,多个区组组成了段,多个段组成了表空间。

4.2.1 小区例子

在小区中,每一个房间号就是页号,房间就是一个个页,而一个单元楼就是由多个房间组成(页),对应区,而多个连续的单元楼又组成一栋楼,对应区组,所有栋楼组成一个小区,小区就是一个段,只是有的小区是公寓形式的小区,有的小区是居民楼,有的是别墅区,根据存储的数据类别进行区别。

4.3 为什么要使用页这个管理单元

⾸先要明确⼀点,MySQL中的⻚是应⽤层的⼀个概念,是MySQL根据⾃⾝的应⽤场景,定义的⼀种数据结构。

通常操作系统中的⽂件系统在管理磁盘⽂件时以4KB⼤⼩为⼀个管理单元,称为"数据块",但是在数据库的应⽤场景⾥,查询时数据量都⽐较⼤,如果也使⽤4KB做数据存储的最⼩的单元,就显的有点⼩了,同时会造成频繁的磁盘I/O,导致降低效率;

所以MySQL根据⾃⾝情况定义了⼤⼩为16KB的⻚,做为磁盘管理的最⼩单位;

每次内存与磁盘的交互⾄少读取⼀⻚,所以在磁盘中每个⻚内部的地址都是连续的,之所以这样做,是因为在使⽤数据的过程中,根据局部性原理,将来要使⽤的数据⼤概率与当前访问的数据在空间上是临近的,所以⼀次从磁盘中读取⼀⻚的数据放⼊内存中,当下次查询的数据还在这个⻚中时就可以从内存中直接读取,从⽽减少磁盘I/O,提⾼性能。

4.3.1 为什么默认是16KB(接水例子)

当我们在接水时,常常是使用容器来装水,每次装满然后放到水缸或一个大容器中。水管连接的水库就像是磁盘,我们每次通过水管接水就好比读写一次磁盘,每次接完水,又要放到水缸中。水缸好比一块内存区域,而如果我的接水容器很小,那么每接一次固定体积的水,需要的接水次数要比使用更大接水容器的接水次数多,导致效率更低;但如果我的接水容器过大,而我不需要那么多的水,也就是,导致每次会接出额外的水,也会导致内存浪费和效率低。因此,选定一个适当的容器大小(页大小)是非常重要的,经过计算,选定16KB作为MySQL的默认页大小。

4.3.2 页默认16KB不会产生浪费吗

InnoDB 默认使用 16KB 的页大小(可通过 innodb_page_size 调整),看似可能浪费空间,但实际上通过 局部性原理(Locality Principle) 实现了空间与性能的最佳平衡。

局部性原理的核心思想

  • 时间局部性(Temporal Locality)
    如果一个数据被访问,那么它很可能在短时间内再次被访问(比如事务频繁修改同一条记录)。
  • 空间局部性(Spatial Locality)
    如果一个数据被访问,那么它附近的数据也可能很快被访问(比如范围查询、索引遍历)。

4.4 数据页的基本特性

InnoDB 的数据页(Page)是存储和管理的最小物理单元,其设计直接影响数据库的性能和可靠性。以下是核心特性详解:


4.4.1 页的物理属性
特性说明
固定大小默认 16KB(可通过 innodb_page_size 调整为 4K/8K/16K/32K/64K)
不可分割即使只存1字节数据,也会占用完整16KB空间
唯一标识通过 (space_id, page_no) 全局定位(如 (1, 123) 表示表空间1的第123页)

修改页大小(需初始化前配置)

# my.cnf
[mysqld]
innodb_page_size=32K  # 重启后不可更改

4.4.2 页的逻辑结构
┌───────────────────────────────────────┐
│            InnoDB Page (16KB)         │
├───────────────────┬──────────────────┤
│      File Header  (38字节)             │
├───────────────────┼──────────────────┤
│      Page Header  (56字节)             │
├───────────────────┼──────────────────┤
│      Infimum + Supremum Records       │
├───────────────────┼──────────────────┤
│      User Records (实际数据行)         │
├───────────────────┼──────────────────┤
│      Free Space   (未分配空间)         │
├───────────────────┼──────────────────┤
│      Page Directory (页目录)           │
├───────────────────┼──────────────────┤
│      File Trailer (8字节)              │
└───────────────────┴──────────────────┘

4.4.3 核心组成部分详解
1. File Header(文件头)
字段大小作用
FIL_PAGE_SPACE_ID4字节表空间ID
FIL_PAGE_OFFSET4字节页号(在表空间内的物理偏移)
FIL_PAGE_TYPE2字节页类型(0x45BF=数据页,0x0002=索引页等)
FIL_PAGE_LSN8字节最后修改的日志序列号(用于崩溃恢复)
2. Page Header(页头)
字段说明
PAGE_N_DIR_SLOTS页目录中的槽位数(用于二分查找)
PAGE_HEAP_TOP空闲空间起始位置(动态增长方向)
PAGE_N_HEAP页内记录数(包括Infimum/Supremum伪记录)
PAGE_LAST_INSERT最后插入记录的位置
3. Infimum + Supremum Records
  • 伪记录:每个页固定有这两条系统记录
    • Infimum:比任何主键都小的虚拟记录(标识页内最小值)
    • Supremum:比任何主键都大的虚拟记录(标识页内最大值)
  • 作用:作为B+树叶子节点的边界标记
4. User Records(用户记录)
  • 存储格式:

    | 变长字段长度列表 | NULL标志位 | 记录头 | 主键值 | 事务ID | 回滚指针 | 列数据... |
    
  • 记录头结构:

    struct rec_header {uint8_t deleted_flag;    // 删除标记uint8_t min_rec_flag;   // 非叶子节点最小记录标记uint8_t n_owned;        // 该记录拥有的记录数(页目录用)uint16_t heap_no;       // 记录在堆中的序号uint8_t record_type;    // 记录类型(0=普通,1=非叶子节点等)uint16_t next_record;   // 下一条记录的相对位置
    };
    
5. Page Directory(页目录)
  • 作用:加速页内记录查找(类似索引的索引)

  • 实现原理:

    • 将记录分组(每组4-8条),记录每组最后一条记录的地址到槽位(Slot)
    • 查找时先二分定位槽位,再在组内线性搜索
    槽位0 → 记录A (heap_no=2)
    槽位1 → 记录D (heap_no=5)
    槽位2 → 记录G (heap_no=8)
    
6. File Trailer(文件尾)
  • 8字节校验和:用于检测页是否完整写入磁盘(防止部分写问题)

4.4.4 页的运行时行为
1. 记录插入流程
Client Page 插入新记录 从Free Space分配空间 更新User Records链表 必要时重组页目录槽位 返回插入位置 Client Page
2. 空间回收
  • 删除记录:仅标记 deleted_flag,空间不立即回收
  • 空间重用:新插入记录优先使用已删除的空间(通过 PAGE_FREE 链表管理)
3. 页分裂阈值
  • 触发条件:剩余空间不足容纳新记录时

    -- 查看页填充状态
    SHOW ENGINE INNODB STATUS\G
    -- 在"BUFFER POOL AND MEMORY"段查找"Page size"
    

4.4.5 页类型扩展
页类型标识值用途
数据页0x45BF存储表数据
索引页0x0002非叶子节点的索引记录
Undo日志页0x0002存储事务回滚日志
系统页0x0003数据字典信息
BLOB页0x0004存储溢出的大对象数据

4.4.6 性能优化建议
  1. 避免行溢出

    • 单行数据尽量不超过页大小的一半(约8KB)
    -- 检查大记录
    SELECT avg_row_length FROM information_schema.tables 
    WHERE table_name='your_table';
    
  2. 监控页分裂

    -- 通过innodb_metrics监控
    SELECT name, count FROM information_schema.INNODB_METRICS
    WHERE name LIKE '%page_split%';
    
  3. 优化主键设计

    • 自增主键可减少页分裂(顺序插入)
    • 避免随机主键(如UUID)导致频繁分裂

4.5 大范围查询优化:区(Extent)与顺序I/O

当查询涉及跨越多页的数据时,InnoDB 通过 区(Extent)预读机制 解决随机 I/O 性能问题。以下是深度解析:

4.5.1 核心问题:随机I/O的性能瓶颈
  • 场景示例:

    -- 查询跨越多个页的数据
    SELECT * FROM orders WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31';
    
  • 性能陷阱:

    • 若数据分散在不同页(物理不连续),需多次磁盘寻址 → 高延迟
    • 传统机械硬盘随机I/O性能可能比顺序I/O 低100倍
4.5.2 InnoDB的解决方案:区(Extent)
1. 区的定义
概念说明
物理组成连续64个页(默认16KB/页 × 64 = 1MB
分配策略- 小表:使用碎片区中的零散页 - 大表(>32页):整区分配
管理单元通过 XDES页(Extent Descriptor) 跟踪区的使用状态

新表默认7个初始页,放入碎片区,达到32个页的时候,后续每次都会申请一个完整的区。

2. 区如何提升性能
  • 顺序I/O优化:

    查询请求
    加载首个数据页
    触发预读机制
    顺序加载同区的后续页
    减少磁头寻址时间
4.5.3 关键优化机制
1. 预读(Read-Ahead)
  • 线性预读:

    • 顺序访问一个区中超过 innodb_read_ahead_threshold(默认56)页时,异步预读下一个区
    SHOW VARIABLES LIKE 'innodb_read_ahead_threshold';
    
  • 随机预读:

    • 当检测到同一个区中的随机访问热点时,预读剩余页(默认关闭,因SSD普及)SET GLOBAL
    SET GLOBAL innodb_random_read_ahead=ON;  -- 谨慎使用
    
2. 区组(Extent Group)
  • 物理连续:256个区(256MB)为一组,进一步提升顺序访问效率
  • 分配策略
新建表 → 从空闲区组分配
大表扩容 → 优先分配相邻区组
4.5.4 区如何管理页

区描述符(XDES)

struct xdes_entry {uint32_t state;    // 区状态(FREE/FRAG/FULL)uint64_t bitmap;   // 页使用位图(64位对应64个页)list_node_t list;  // 所属链表
};

4.6 段的作用

4.6.1 核心定位

InnoDB 的 段(Segment) 是比区(Extent)更高层级的逻辑管理单元,用于区分不同功能的数据存储区域,主要解决两类问题:

  1. 空间隔离:避免索引节点与数据页混用导致碎片化
  2. 性能优化:针对B+树不同部位(叶子/非叶子)采用差异化管理
4.6.2 分类与功能
段类型存储内容管理策略典型场景
叶子节点段存储实际行记录优先分配完整区(1MB)主键索引的叶子层
非叶子节点段存储B+树索引目录允许使用碎片区中的零散页索引的根节点和中间层
回滚段Undo日志记录固定大小的独立区组事务回滚和MVCC
4.6.3 段的空间管理机制
1. 分配策略对比
新建索引
分配非叶子节点段
分配叶子节点段
允许使用碎片区零散页
优先分配完整连续区
2. 碎片区(Fragmented Extent)的特殊性
  • 共用池:所有非叶子节点段共享碎片区资源

  • 分配逻辑:

    if 段类型 == 叶子节点段:分配完整区
    else:从碎片区抓取零散页(若碎片区不足则申请新区)
    
3. 段与区的映射关系
  • 每个段通过 INODE Entry结构维护其管理的区列表:

    struct inode_entry {space_id_t space_id;    // 所属表空间list_t free_extents;    // 空闲区列表  list_t full_extents;    // 已满区列表list_t frag_extents;    // 碎片区引用
    };
    

5. 页的结构

5.1 页大小设置

通过参数innodb_page_size配置(4K/8K/16K/32K/64K),需在数据库初始化时设置:

[mysqld]
innodb_page_size=32K

5.2 页的分类

页类型标识值用途
数据页0x45BF存储表记录
索引页0x0002存储B+树非叶节点
Undo页0x0002存储事务回滚日志
XDES页0x0003管理区分配状态
段信息页0x0004存储INODE条目

5.3 页头/页尾结构

5.3.1 ⻚头 - File Header
  • ⻚号: FIL_PAGE_OFFSET 占⽤ 4Byte ,相当于⻚的⾝份证号,通过这个⻓度可以计算出每个InnoDB表中最多可以拥有 2^(48)-1约42亿 个⻚,表空间第⼀个⻚编号从0开始,之后的⻚号分别是1,2,3…依此类推,具体⻚的偏移量计算公式为:⻚号 * 每⻚⼤⼩;那么按照每个⻚默认16KB⼤⼩计算,⼀个表空间最⼤容量为 2^(48) * 16KB = 64TB ,这也是InnoDB表空间最⼤容量是64T的原因;
  • 上⼀⻚⻚号: FIL_PAGE_PREV
  • 下⼀⻚⻚号: FIL_PAGE_NEXT 多个⻚通过这两个信息组成双向链表,即使不同的⻚地址不连续,也可以通过链表连接
  • 表空间ID: FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID ,当前⻚属于哪个表空间
  • ⻚类型: FIL_PAGE_TYPE ,数据⻚对应的⻚类型是 FIL_PAGE_INDEX = 0x45BF
  • 最近⼀次修改的LSN: FIL_PAGE_LSN ,占⽤8Byte
  • 已被刷到磁盘的LSN: FIL_PAGE_FILE_FLUSH_LSN ,占⽤8Byte
  • 校验和: FIL_PAGE_SPACE_OR_CHKSUM ,⽤于⻚的完整性校验
5.3.2 ⻚尾 - File Trailer
  • 最近⼀次修改的LSN
  • 校验和:对应⻚头中的校验和

如果在数据传输的过程中数据丢失或异常中断,导致⼀个数据⻚不完整就可以通过⻚头和⻚尾的校验和进⾏验证,验证算法默认使⽤ CRC32。

5.4 页主体结构

5.4.1 数据行格式(重点)
| 变长字段长度列表 | NULL标记位 | 头信息 | 主键值 | 事务ID | 回滚指针 | 列数据...
1. 变长字段长度列表

InnoDB的变长字段长度列表是行记录中用于存储可变长度字段实际占用字节数的数据结构,主要处理:

  • 可变长度类型VARCHARVARBINARYTEXTBLOB
  • NULL值标记:与NULL值列表配合使用

基础结构

| 字段1长度 | 字段2长度 | ... | 字段N长度 | 实际数据...
  • 长度表示:
    • 1字节:当长度 ≤ 127字节
    • 2字节:当长度 > 127字节(最高位为标志位)
  • 存储顺序逆序排列(字段N的长度在最前面)

text、blob特别处理

当字段使用text、blob,并且数据量非常大时,真实数据就不会存储在该行了,而是存储在溢出页中,真实数据区使用20个字节溢出指针存储位置信息

溢出指针:

| 空间ID(4字节) | 溢出页号(4字节) | 偏移量(8字节) | 数据长度(4字节) |
2. NULL标记位

NULL值列表是InnoDB行格式中专门标记NULL字段的位图结构,主要解决:

  1. 空间优化:避免为NULL值分配存储空间
  2. 查询加速:快速判断字段是否为NULL

存储规则

特性说明
存储位置位于行记录的起始部分,在变长字段长度列表之后
位图大小每个字段占1bit,按8bit对齐(不足补0)
标记方式1表示NULL,0表示非NULL
字段顺序按照列定义的逆序排列(与变长字段长度列表一致)
3. 头信息(40BIT)
  • deleted_flag:删除标记
  • min_rec_flag:用于标识B+树非叶子节点中的最小边界记录,其具体表现为:
    • 当值为1时:表示该记录是当前非叶子节点中的最小目录项记录
    • 当值为0时:普通记录或叶子节点记录
  • n_owned:目录槽中行数,只有槽的最后一行该数据才有效
  • heap_no:记录堆序号(从2开始)
  • record_type:记录行类型,0=普通记录,1=非叶节点记录
  • next_record:下一行的地址偏移量
4. 主键值、事务ID、回滚指针

这三项是InnoDB数据行默认生成的

主键值(Primary Key)

数据行根据主键值进行排序,方便顺序IO,提高查找效率和页目录的使用

  • 存储位置:紧跟在记录头(Record Header)之后
  • 存储规则:
    • 如果表定义了主键,直接存储主键值
    • 如果没有主键,但存在非NULL唯一索引,存储第一个唯一索引的值
    • 如果都没有,InnoDB自动生成6字节的DB_ROW_ID作为隐藏主键

事务ID(DB_TRX_ID)

  • 作用:标记最后修改该行的事务
  • 存储位置:主键值之后
  • 大小:6字节
  • 特性:
    • 用于MVCC(多版本并发控制)
    • 事务开始时从全局事务ID生成器分配

回滚指针(DB_ROLL_PTR)

  • 作用:指向Undo Log中的历史版本

  • 存储位置:事务ID之后

  • 大小:7字节

  • 结构:

    | Undo Log位置 (4字节) | 历史记录序号 (2字节) | 标志位 (1字节) |
    
5.4.2 首尾记录标识
  • Infimum:虚拟最小记录(heap_no=0)
  • Supremum:虚拟最大记录(heap_no=1)
5.4.3 页目录查询
  • 每组4-8条记录建立槽位(Slot)
  • 二分查找定位槽位后线性搜索

页目录的作用:

每个槽存放该组中的最后一个数据行的主键值,通过主键值二分查找页目录,查到数据行在哪一个槽中,读取该槽的最后一个数据行的头信息中的n_owned得到该槽中的行数,然后遍历该组记录。

5.5 事务信息存储

  • 事务ID(db_trx_id):6字节
  • 回滚指针(db_roll_ptr):7字节
  • 通过DB_ROLL_PTR可追溯数据历史版本

6. 行结构

6.1 行格式对比

格式特性适用场景
COMPACT768字节前缀存储兼容老版本
DYNAMIC纯指针存储溢出页默认推荐
COMPRESSED支持透明压缩存储优化
6.1.1 查看行格式
SHOW TABLE STATUS LIKE '表名'\G
-- 或
SELECT ROW_FORMAT FROM information_schema.TABLES 
WHERE TABLE_NAME='表名';
6.1.2 指定行格式
CREATE TABLE t1 (id INT) ROW_FORMAT=DYNAMIC;
ALTER TABLE t1 ROW_FORMAT=COMPRESSED;
6.1.3 DYNAMIC行特性
  • 溢出处理:当行超过页大小时,仅存储20字节指针
  • NULL优化:专用位图标记NULL列(每列1bit)
6.1.4 变长字段存储
  • 长度≤127字节:1字节存储长度
  • 长度>127字节:2字节存储长度
  • TEXT/BLOB:始终使用溢出页
6.1.5 溢出指针结构
struct overflow_ptr {uint32 space_id;uint32 page_no;uint64 offset;uint32 data_len;
};
6.1.6 格式差异对比
特性REDUNDANTCOMPACTDYNAMIC
行头6字节5字节5字节
NULL处理字段固定长度位图标记位图标记
溢出处理部分存储部分存储全溢出

附录:InnoDB存储全景图

表空间
叶子节点段
非叶子节点段
区组
行记录

相关文章:

MySQL——学习InnoDB(1)

MySQL——学习InnoDB(1) 文章目录 MySQL——学习InnoDB(1)1. InnoDB的前世今生1.1 诞生发展1.2 核心设计1.3 关键进化 2. InnoDB和MyISAM在性能和安全上的区别2.1 性能对比2.2 安全对比 3. InnoDB架构图(内存结构磁盘结…...

QT中多线程写法

转自个人博客:QT中多线程写法 1. QThread及moveToThread() 使用情况: 多使用于需要将有着复杂逻辑或需要一直占用并运行的类放入子线程中执行的情况,moveToThread是将整个类的对象移入子线程。 优缺点: 优点:更符合…...

css 二维码始终显示在按钮的正下方,并且根据不同的屏幕分辨率自动调整位置

一、需求 “求职入口” 下面的浮窗位置在其正下方&#xff0c;并且浏览器分辨的改变&#xff08;拖动浏览器&#xff09;&#xff0c;位置依旧在最下方 二、实现 <div class"btn_box"><div class"btn_link id"js-apply">求职入口<di…...

STM32 认识STM32

目录 什么是嵌入式&#xff1f; 认识STM32单片机 开发环境安装 安装开发环境 开发板资源介绍 单片机开发模式 创建工程的方式 烧录STM32程序 什么是嵌入式&#xff1f; 1.智能手环项目 主要功能有&#xff1a; 彩色触摸屏 显示时间 健康信息&#xff1a;心率&#…...

关于 CSDN的C知道功能模块 的详细解析,包括 新增的AI搜索(可选深度思考) 和 智能体功能 的具体说明及对比分析

以下是关于 CSDN的C知道功能模块 的详细解析&#xff0c;包括 新增的AI搜索&#xff08;可选深度思考&#xff09; 和 智能体功能 的具体说明及对比分析&#xff1a; 一、C知道核心功能模块详解&#xff08;基础功能&#xff09; &#xff08;参考前文内容&#xff0c;此处略…...

Vue--组件练习案例

图片轮播案例&#xff1a; <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><title>Title</title></head><body><!--轮播图片--><div id"app"><h1>轮播图</h1…...

Sentinel源码—1.使用演示和简介一

大纲 1.Sentinel流量治理框架简介 2.Sentinel源码编译及Demo演示 3.Dashboard功能介绍 4.流控规则使用演示 5.熔断规则使用演示 6.热点规则使用演示 7.授权规则使用演示 8.系统规则使用演示 9.集群流控使用演示 1.Sentinel流量治理框架简介 (1)与Sentinel相关的问题 …...

空间信息可视化——WebGIS前端实例(二)

技术栈&#xff1a;原生HTML 源代码&#xff1a;CUGLin/WebGIS: This is a project of Spatial information visualization 5 水质情况实时监测预警系统 5.1 系统设计思想 水安全是涉及国家长治久安的大事。多年来&#xff0c;为相应国家战略&#xff0c;诸多地理信息领域的…...

高并发内存池(前言介绍)

高并发内存池项目介绍 1.项目介绍2.项目的知识储备要求3.了解池化技术及内存池4.本次项目中内存池解决的问题5.malloc 1.项目介绍 此项目是实现一个高并发的内存池&#xff0c;它的原型是google的一个开源项目tcmalloc&#xff0c;tcmalloc全程Thread-Caching Malloc&#xff…...

误译、值对象和DDD伪创新-《分析模式》漫谈56

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 “Analysis Patterns”的第14章“类型模型设计模板模式”原文&#xff1a; Examples of such object types are the classic built-in data types of programming environments: inte…...

Java单例模式:实现全局唯一对象的艺术

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、什么是单例模式&#xff1f; 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;确保一个类只有一个实例&#xff0c…...

机器学习项目二:帕金森病检测

目录 下载数据 一、导入相关包 二、数据加载 三、特征工程 四、构建模型 五、评估与可视化 六、程序流程 七、完整代码 一、导入相关包 # 导入库部分 import numpy as np # 数值计算基础库 import pandas as pd # 数据处理库 from sklearn.preprocessing import MinMaxS…...

FreeDogs:AI、区块链与迷因文化的深度融合

引言 在 Web3 时代&#xff0c;人工智能&#xff08;AI&#xff09;、区块链技术和迷因文化的结合催生了一种全新的去中心化生态系统。FreeDogs 项目作为这一领域的创新代表&#xff0c;通过独特的技术与文化融合模式迅速受到关注。它利用 AI 驱动的智能营销网络推动迷因文化的…...

《组合优于继承:构建高内聚低耦合模块的最佳实践》

《组合优于继承:构建高内聚低耦合模块的最佳实践》 一、引言:编程范式中的选择 在软件设计中,继承和组合是两个重要的设计模式。继承(Inheritance)常被用来实现代码复用,但滥用继承容易导致脆弱的类层次结构,增加耦合度和维护成本。而组合(Composition)通过将功能分解…...

机器学习02——RNN

一、RNN的基本概念 定义 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种用于处理序列数据的神经网络架构。它与传统的前馈神经网络&#xff08;如多层感知机&#xff09;不同&#xff0c;RNN具有“记忆”功能&#xff0c;能够利用前一时…...

Java基础——面试自我总结

1、String类中常用方法和equals区别 答&#xff1a;对于和equals这两个都是用来比较判断是否相等&#xff0c;其中用来判断两个变量的值是否相等&#xff0c;变量的值的类型分为基本数据类型和引用数据类型。对于&#xff0c;基本数据类型是直接进行值比较&#xff0c;而对于引…...

低功耗设计:Level Shift的种类(以SAED EDK 32/28nm工艺库为例)

在多电压设计中&#xff0c;当信号从一个电压域跨越到另一个电压域时&#xff0c;需要使用电压转换器(Level Shift)。它的工作方式类似于缓冲器&#xff0c;但其输入和输出使用不同的电压&#xff0c;作用是将一个逻辑信号从一个电压转换为另一个电压&#xff0c;并在输入到输出…...

UE5 Chaos :渲染网格体 (Render Mesh) 和模拟网格体 是如何关联的?为什么模拟网格体 可以驱动渲染网格体?

官方文献&#xff1a;https://dev.epicgames.com/community/learning/tutorials/pv7x/unreal-engine-panel-cloth-editor 这背后的核心是一种常见的计算机图形学技术&#xff0c;通常称为代理绑定 (Proxy Binding) 或 表面变形传递 (Surface Deformation Transfer)。 关联机制…...

Fiddler为什么可以看到一次HTTP请求数据?

1、作为代理服务器 Fiddler作为代理服务器&#xff0c;拦截了设备与互联网服务器之间的所有HTTP和HTTPS流量。当客户端&#xff08;如浏览器&#xff09;发送请求时&#xff0c;请求先到达Fiddler&#xff0c;然后由Fiddler转发到目标服务器&#xff1b;服务器的响应也会返回给…...

RAG(Retrieval-Augmented Generation)召回算法是检索增强生成模型中的关键组件

RAG&#xff08;Retrieval-Augmented Generation&#xff09;召回算法是检索增强生成模型中的关键组件&#xff0c;其核心目标是从大规模文档库中高效检索与输入查询相关的信息&#xff0c;以辅助生成模型产生更准确的回答。以下是该算法的关键点解析&#xff1a; ### 1. **核…...

[NOIP 2003 普及组] 栈 Java

import java.io.*;public class Main {public static void main(String[] args) throws IOException {BufferedReader br new BufferedReader(new InputStreamReader(System.in));int n Integer.parseInt(br.readLine());int[] dp new int[n 1];dp[0] 1; // 空序列只有一种…...

5.5 GitHub数据秒级分析核心揭秘:三层提示工程架构设计解析

GitHub Sentinel Agent 分析报告功能设计与实现 关键词:GitHub 数据分析, 提示工程设计, Pull Request 分析, Issues 跟踪, 竞品对比 项目进展报告生成功能设计 报告生成模块是 GitHub Sentinel 的核心功能,通过三层嵌套式提示工程架构实现深度分析: #mermaid-svg-vdHRUan…...

PE文件(十五)绑定导入表

我们在分析Windows自带的一些程序时&#xff0c;常常发现有的程序&#xff0c;如notepad&#xff0c;他的IAT表在文件加载内存前已经完成绑定&#xff0c;存储了函数的地址。这样做可以使得程序是无需修改IAT表而直接启动&#xff0c;这时程序启动速度变快。但这种方式只适用于…...

如何快速部署基于Docker 的 OBDIAG 开发环境

很多开发者对 OceanBase的 SIG社区小组很有兴趣&#xff0c;但如何将OceanBase的各类工具部署在开发环境&#xff0c;对于不少开发者而言都是比较蛮烦的事情。例如&#xff0c;像OBDIAG&#xff0c;其在WINDOWS系统上配置较繁琐&#xff0c;需要单独搭建C开发环境。此外&#x…...

Multimodal-CoT与MCP的融合医疗AI编程路线探析

引言 在医疗AI领域,多模态数据融合与模块化系统设计是提升诊断精度和临床实用性的关键。Multimodal Chain-of-Thought(Multimodal-CoT)通过构建多源数据的推理链增强决策透明度,而Model Context Protocol(MCP)作为标准化接口协议,为AI系统提供灵活的数据源集成能力。两…...

基于单片机的智能养生油炸炉系统设计与实现

标题:基于单片机的智能养生油炸炉系统设计与实现 内容:1.摘要 本文针对传统油炸炉功能单一、无法满足现代养生需求的问题&#xff0c;设计并实现了基于单片机的智能养生油炸炉系统。通过采用STC89C52单片机作为控制核心&#xff0c;结合温度传感器、液位传感器、继电器等硬件&…...

MySQL流程控制

一&#xff1a;介绍 在 MySQL 中&#xff0c;流程控制语句用于控制存储过程和自定义函数中的程序流程。主要的流程控制语句包括&#xff1a;IF 语句、CASE 语句、LOOP 语句、LEAVE 语句、ITERATE 语句、REPEAT 语句和 WHILE 语句 &#xff08;1&#xff09;&#xff1a;if条件…...

在思科模拟器show IP route 发现Gateway of last resort is not set没有设置最后的通道

如果在show ip route的时候出现没有设置最后的通道Gateway of last resort is not set Switch#show ip route Codes: C - connected, S - static, I - IGRP, R - RIP, M - mobile, B - BGPD - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter areaN1 - OSPF NSSA exte…...

Java雪花算法

以下是用Java实现的雪花算法代码示例&#xff0c;包含详细注释和异常处理&#xff1a; 代码下面有解析 public class SnowflakeIdGenerator {// 起始时间戳&#xff08;2020-01-01 00:00:00&#xff09;private static final long START_TIMESTAMP 1577836800000L;// 各部分…...

【中大厂面试题】TCP 校招 java 后端最新面试题

TCL&#xff08;一面&#xff09; 1. Spring 初始化Bean前要做什么&#xff1f;有几种方式 在 Spring 容器调用 Bean 的初始化方法&#xff08;如 init-method、PostConstruct 等&#xff09;之前&#xff0c;会按顺序完成以下关键步骤&#xff1a;实例化 → 属性注入 → Aw…...

【教学类-102-11】蝴蝶外轮廓01——Python对黑白图片进行PS填充三种颜色+图案描边+图案填充白色+制作1图2图6图24图

背景需求: 用Python,对白色255背景的图片进行了透明化、制作点状或线段的描边裁剪线 【教学类-102-10】剪纸图案全套代码09——Python线条虚线优化版04(原图放大白背景)+制作1图2图6图24图-CSDN博客文章浏览阅读1k次,点赞27次,收藏8次。【教学类-102-10】剪纸图案全套代…...

【数据库系统概论】第3章 SQL(四)视图(超详细)

视图&#xff08;View&#xff09;是数据库中的虚拟表 通过执行查询定义并存储在数据库中&#xff0c;可以像普通表一样被查询和使用。 视图本身并不存储数据&#xff0c;而是基于一个或多个表的查询结果动态生成。 视图的概念 视图( View )是由其它表或视图上的查询所定义…...

HTTP:六.HTTP代理相关介绍

什么是HTTP代理 代理是指获授权代表他人执行操作的人员,代理服务器在在线世界中提供此操作。 代理服务器 充当用户和互联网之间的网关,并防止访问网络以外的任何人。通过 Web 浏览器定期访问互联网,使用户能够直接与网站连接。但是代理充当中间人,代表用户与网页通信。 当…...

【Python爬虫】详细工作流程以及组成部分

目录 一、Python爬虫的详细工作流程 确定起始网页 发送 HTTP 请求 解析 HTML 处理数据 跟踪链接 递归抓取 存储数据 二、Python爬虫的组成部分 请求模块 解析模块 数据处理模块 存储模块 调度模块 反爬虫处理模块 一、Python爬虫的详细工作流程 在进行网络爬虫工…...

深入解析UML图:版本演变、静态图与动态图详解

目录 前言1 UML的版本演变1.1 UML 1.x阶段&#xff1a;统一的开始1.2 UML 2.x阶段&#xff1a;功能的扩展与深化 2 UML图的分类概述3 UML静态图详解3.1 类图&#xff08;Class Diagram&#xff09;3.2 对象图&#xff08;Object Diagram&#xff09;3.3 组件图&#xff08;Comp…...

老旧测试用例生成平台异步任务与用户通知优化

在现代 Web 开发中&#xff0c;异步任务处理和用户通知是两个重要的功能。由于老旧测试平台【测试用例生成平台&#xff0c;源码分享】进行智能化升级后&#xff0c;未采用异步任务处理&#xff0c;大模型推理时间较长&#xff0c;导致任务阻塞&#xff0c;无法处理其他任务&am…...

数据结构初阶:队列

本篇博客主要讲解队列的相关知识。 目录 1.队列 1.1 概念与结构 1.2 队列头文件&#xff08;Queue.h&#xff09; 1.2.1 定义队列结点结构 1.2.2 定义队列的结构 1.3 队列源代码&#xff08;Queue.h&#xff09; 1.3.1 队列的初始化 1.3.2 队列的销毁 1.3.3 入队---队尾 1…...

苍穹外卖。12 数据统计

12.1 工作台 12.1.1 需求分析与设计 12.1.2 代码导入 12.1.3 测试 测试通过 12.2 Apache POI 12.2.1 需求分析与设计 12.2.2 案例 column表示索引行...

WebSocket 和 HTTP长轮询

一、HTTP长轮询&#xff08;Long Polling&#xff09; 1. 工作原理 传统轮询&#xff08;低效&#xff09;&#xff1a;客户端每隔几秒向服务器发一次请求&#xff0c;问“有新数据吗&#xff1f;”&#xff0c;即使服务器没有数据也会立即返回“无”。长轮询&#xff08;改进…...

高等数学同步测试卷 同济7版 试卷部分 上 做题记录 第三章微分中值定理与导数的应用同步测试卷 B 卷

第三章微分中值定理与导数的应用同步测试卷 B 卷 一、单项选择题(本大题共5小题,每小题3分,总计15分) 1. 2. 3. 4. 5. 二、填空题(本大题共5小题,每小题3分,总计15 分) 6. 7. 8. 9. 10. 三、求解下列各题(本大题共5小题,每小题6分,总计 3…...

生成式引擎优化(GEO)发展史与行业标准演变

一、生成式引擎优化&#xff08;GEO&#xff09;发展史与行业标准演变 随着 ChatGPT、Bard、Claude、文心一言等生成式AI搜索产品快速发展&#xff0c;GEO&#xff08;Generative Engine Optimization&#xff0c;生成式引擎优化&#xff09;也应运而生&#xff0c;成为继SEO、…...

美客多自养号测评技术解析:如何低成本打造安全稳定的测评体系

美客多&#xff08;MercadoLibre&#xff09;自养号测评系统的搭建需综合考虑硬件、软件、网络环境及操作流程的合规性&#xff0c;以下是基于多篇行业指南整理的核心步骤与要点&#xff1a; 一、前期规划与准备 1. 明确目标与规则 • 确定测评目的&#xff08;如提升产品曝…...

STM32单片机入门学习——第36节: [11-1] SPI通信协议

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.14 STM32开发板学习——第36节: [11-1] SPI通信协议 前言开发板说明引用解答和科普一…...

Qt QML - qmldir使用方法详解

以实际例子看qmldir的使用 1.搞一个qmldir2.让QML找到你的qmldir &#xff08;重点&#xff09;.pro 工程文件QQmlApplicationEngine加载主QML处 3.用起来你的模块 qmldir是Qt QML模块化的基石&#xff0c;其设计初衷是为解决QML文件的组织、复用和依赖管理问题,。只需要在每个…...

AI大模型赋能工业制造:智能工厂的全新跃迁路径

📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 引言:从自动化到智造化,工业领域的AI革命正悄然发生 在过去几十年中,制造业经历了机械化、电气化和自动化三次浪潮。如今,第四次工业革命——以人工智能、大数据、云计算、物联网为代表的“工业…...

LanDiff:赋能视频创作,语言与扩散模型的融合力量

自从 Wan 2.1 发布以来&#xff0c;AI 视频生成领域似乎进入了一个发展瓶颈期&#xff0c;但这也让人隐隐感到&#xff1a;“DeepSeek 时刻”即将到来&#xff01;就在前几天&#xff0c;浙江大学与月之暗面联合推出了一款全新的文本到视频&#xff08;T2V&#xff09;生成模型…...

Windows 图形显示驱动开发-WDDM 1.2功能~显示设备的容器id支持

容器 ID 设备驱动程序接口 (DDI) 在显示微型端口驱动程序中实现此函数和结构&#xff1a; DxgkDdiGetChildContainerIdDXGK_CHILD_CONTAINER_ID 容器 ID 说明 监视设备中的新功能可以提供更好的用户体验。 具体而言&#xff0c;通用串行总线 (USB) 集线器是监视器上用于连…...

基于PyQt5和OpenCV的传统图像分割应用UI程序

目录 1. 程序概述 2. 用户界面设计 主窗口布局 图像显示区域 控制面板区域 3. 核心功能实现 图像处理功能 关键方法 4. 特色实现 区域生长算法改进 分水岭算法改进 GrabCut算法改进 5. 用户体验优化 6. 技术栈 7. 使用说明 8. 完整代码 9. 测试结果 本文实现了…...

java使用HTTP实现多线程爬取数据

Java中使用HTTP多线程爬取数据。首先&#xff0c;我得理解他们的需求。可能想要高效地抓取大量网页数据&#xff0c;而单线程可能不够快&#xff0c;所以需要多线程来提高效率。不过&#xff0c;多线程爬虫需要考虑的问题挺多的&#xff0c;比如线程安全、请求频率控制、异常处…...

08【基础学习】串口通信(三):收发数据包+数据校验

收发数据包数据校验 1、和校验异或校验1.1、HEX固定长度数据包校验1.2、HEX不固定长度数据包校验 2、CRC校验 1、和校验异或校验 和校验&#xff1a;将接收到的数据全部相加后&#xff0c;取结果的最后一个字节的数据 异或校验&#xff1a;将接收到的数据全部相异或后&#xff…...