MySQL进阶突击系列(09)数据磁盘存储模型 | 一行数据怎么存?

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: 文中详细介绍了MySQL数据库中一行数据在磁盘上的存储机制,包括表空间、段、区、页和行的具体结构,以及如何设计和优化行数据存储以提高性能。

读书笔记:当一个人存在‘只有目标综合征’,容易陷入全能自恋状态。具体表现为,当设定一个一个目标后,会自动忽略时间、空间、过程维度信息,然后急切甚至要求立即实现目标。如果目标没有实现,将出现自我否定和破灭的想法。简单的把目标和‘我’混为一体,这是单一自恋维度的病态,会让人进入焦虑状态。打破单一自恋维度的方法,可以与周边建立连接,进入关系维度体验现实,让大自然、亲情友情、还有社会百态来增强现实体验,摆脱思维孤独。


一、前言背景

二、数据存储整体逻辑

2.1 存储地址和具体文件

2.2 表空间-段segement

2.3 表空间-区extent

2.4 表空间-页page

2.5 表空间-行数据row

三、如何设计存放一行数据

3.1 行格式类型

3.2 具体数据构成

3.3 变长字段、定长字段存储

3.4 空null存储

3.5 什么是行溢出现象?


一、前言背景

MySQL的一行数据在磁盘里是如何存放的?一行数据存放后,数据又是如何读取的?

    这两个问题如果详细展开的话,各自至少需要一篇文章才能讲齐全。涉及底层的物理存储、模型设计逻辑,相对而言,会有一些难度以及枯燥乏味,导致去了解和探索的意愿相对也会少一些。保持尽可能详尽又易于理解,篇幅不能过长,避免大家阅读疲惫,今天我们仅探讨【一行数据内容在磁盘如何存放】问题。

二、数据存储整体逻辑

    从逻辑上来讲,一个数据库里由多个表组成,每个表由多行数据组成。每个表的表空间由段segment、区extent、页page、行row组成。具体:

一个表空间由多个段segement组成。

一个段segement有多个数据区extent组成,256个数据区,是一组数据区。

一个数据区extent对应64个连续的数据页,也就是一个数据区是1Mb大小。

一个页page,是16kb大小,每个页里面存放具体行数据。

接下来,我们具体展开看看表空间的各个部分作用。

2.1 存储地址和具体文件

    一个数据库以及相关表的数据在磁盘存放目录地址,可以通过命令查看:

show variables like '%datadir%';

默认数据文件地址目录是:/usr/local/var/mysql

每个数据库,都有单独的文件夹,存放对应表数据文件。

比如skd的数据库,里面有很多个表文件。

在InnoDB存储引擎里,一个表数据由.frm和.ibd后缀文件存储。其中xx.ibd文件存放的就是具体的数据内容,这个文件也被称为独占表空间。而frm文件存放的是表元数据信息和表结构信息。

2.2 表空间-段segement

    段是表空间的逻辑概念,它类型有:数据段、索引段、回滚段。

    每个表通常只有一个数据段,里面存储的是表实际数据,也就是B+树的叶子节点。

    而索引段,就是我们存储引擎InnoDB索引系列说的,B+树的非叶子节点,存储表的索引信息。

    而回滚段,就是对应undo log回滚日志,管理相关回滚日志的区数据。

2.3 表空间-区extent

    表空间的一个区是由连续的64个页组成的空间,区的大小固定为1MB。区的提出和设计,主要是为了使逻辑上相邻的页节点在物理上也尽可能靠近,也就是为了让B+树的双向链表相邻的两个页尽可能挨着,从而减少磁盘随机IO的时间,尽可能实现顺序读写,提升IO效率。

    如果没有区的概念,在B+树索引上,由于每一层都是双向链表,如果单纯以页为单位来分配存储空间,那么链表中相邻的两个页之间的物理位置并不是连续的,可能离得很远,在磁盘读取多个数据页时,可能就会出现大量随机IO,而随机IO速度是非常慢的。

    所以,当表中数据量较大的时候,MySQL为索引分配空间就以区extent为单位分配,确保相关索引数据页地址是连续的,从而为后续数据读写实现顺序读写。

2.4 表空间-页page

    数据页相关分享,在我们系列之前01-08说过很多次,MySQL数据库读取数据并不是以行为单位,而是按页为最小单位去读写的。每个页的默认大小是 16kb。

    InnoDB 存储引擎磁盘管理的最小单元就是页page,数据库每次读写都是以 16KB 为单位,也就是每次从磁盘中最少会读取16kb数据到bufferpool中,或者从内存中把16kb数据刷到磁盘。

2.5 表空间-行数据row

    每页数据,可能存放有多行数据。如果一行数据足够大,比如text类型,一个文本内容非常大,会大于16kb,就需要多个页去存放。

    每行数据,除了要记录具体行数据,也需要记录列字段类型、类型长度、空字段值、还有在MVCC机制原理专题说过,每行数据都有一个row_id,还有更新该行数据的事务id,还有回滚指针地址roll_ptr_id等这些信息。

三、如何设计存放一行数据

3.1 行格式类型

    MySQL 5.6 默认的row_format行格式是Compact,MySQL 5.7版本是dynamic。行格式可以通过创建表时候指定,比如:create table t1(columnxx ...)ROW_FORMAT=compact。

    我们可以通过命令:SHOW TABLE STATUS LIKE '表名';

    比如:SHOW TABLE STATUS LIKE 'sys_dept';查看表的具体格式:

这两种行格式的主要区别在于使用场景上。

    Compact行格式,适用于读操作远多于写操作场景。

    而Dynamic行格式,支持更多高级功能,如表压缩和长列数据的页外存储。适用于需要频繁插入、更新和删除数据的场景。

两个行格式很相近,这里我们对compact格式进行展开举例说明。

3.2 具体数据构成

    上文说过,一行数据内容有:row_id、事务id、roll_ptr回滚地址、真实数据、以及变长字段真实值长度列表、null值字段列表、真实行数据值等其他信息。具体行数据结构如图:

0

    每一行数据都有自己的row_id,如果表没有指定主键或者唯一索引,MySQL内部会默认新增一个row_id作为主键,对每一行数据进行唯一性标识。每行数据的写入或者更新都有对应事务id、以及对应回滚指针,指向之前旧数据地址。

    整个表头信息,大概占用了40bit空间,里面第3bit,是delete_mask,标识该行数据是否被删除。所以MySQL每行数据的删除,不是立马从磁盘物理删除,而是先打标识。

    此外表头信息里还有下一行数据指针地址、行数据类型等附加信息。

3.3 变长字段、定长字段存储

    MySQL的varchar(n)类型字段,由于是变长字段,在解析真实行数据的时候,我们需要记录对应变长字段真实值的长度是多少。比如表有三个字段:name varchar(10),age char(2),sex char(2)。

    某一行数据name列值实际长度可能是5,那通过变长字段实际长度值列表,可以得知后面该字段真实值长度,实现准确解析。

    而定长字段,如果不是空值,在解析真实数据内容,就按指定长度截取解析即可。

3.4 空null存储

    为了节省存储空间以及存储效率,MySQL对行数据字段存在null值的字段,同样参考变长字段长度列表,新增一个null值字段列表。如果该行数据,有N个字段是null值,这个列表就存放相关字段位置,就可以通过该列表表示相关列值为空。

    null值列表是一个bit数组,长度就是允许为空列的个数。比如刚才的表三个字段:name varchar(10),age char(2),sex char(2),三个字段都允许为空。该行name列是空值,age不为空,sex为空。那null值列表bit数组值就是101。

    这个设计,比真实存放null字符串能节省非常多的存储空间。

3.5 什么是行溢出现象?

    行溢出现象就是:如果一行数据很大,就会出现一个数据页无法存储问题,比如存放text文本、blob类型数据容易出现这种情况。MySQL通过多个数据页来存储,加载到bufferpool也是用多个页去存储。



推荐阅读拉丁解牛相关专题系列(欢迎交流讨论):

1、JVM进阶调优系列(3)堆内存的对象什么时候被回收?

2、JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?

3、JVM进阶调优系列(1)类加载器原理一文讲透

4、JAVA并发编程系列(13)Future、FutureTask异步小王子

5、MySQL进阶突击系列(05)突击MVCC核心原理 | 左右护法ReadView视图和undoLog版本链强强联合

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
存储 SQL 关系型数据库
MySQL底层概述—2.InnoDB磁盘结构
InnoDB磁盘结构主要包括表空间(Tablespaces)、数据字典(Data Dictionary)、双写缓冲区(Double Write Buffer)、重做日志(redo log)和撤销日志(undo log)。其中,表空间分为系统、独立、通用、Undo及临时表空间,分别用于存储不同类型的数据。数据字典从MySQL 8.0起不再依赖.frm文件,转而使用InnoDB引擎存储,支持事务原子性DDL操作。
229 100
MySQL底层概述—2.InnoDB磁盘结构
|
1月前
|
存储 SQL 关系型数据库
MySQL底层概述—4.InnoDB数据文件
本文介绍了InnoDB表空间文件结构及其组成部分,包括表空间、段、区、页和行。表空间是最高逻辑层,包含多个段;段由若干个区组成,每个区包含64个连续的页,页用于存储多条行记录。文章还详细解析了Page结构,分为通用部分(文件头与文件尾)、数据记录部分和页目录部分。此外,文中探讨了行记录格式,包括四种行格式(Redundant、Compact、Dynamic和Compressed),重点介绍了Compact行记录格式及其溢出机制。最后,文章解释了不同行格式的特点及应用场景,帮助理解InnoDB存储引擎的工作原理。
MySQL底层概述—4.InnoDB数据文件
|
1月前
|
存储 缓存 关系型数据库
MySQL底层概述—3.InnoDB线程模型
InnoDB存储引擎采用多线程模型,包含多个后台线程以处理不同任务。主要线程包括:IO Thread负责读写数据页和日志;Purge Thread回收已提交事务的undo日志;Page Cleaner Thread刷新脏页并清理redo日志;Master Thread调度其他线程,定时刷新脏页、回收undo日志、写入redo日志和合并写缓冲。各线程协同工作,确保数据一致性和高效性能。
MySQL底层概述—3.InnoDB线程模型
|
17天前
|
SQL 关系型数据库 MySQL
基于SQL Server / MySQL进行百万条数据过滤优化方案
对百万级别数据进行高效过滤查询,需要综合使用索引、查询优化、表分区、统计信息和视图等技术手段。通过合理的数据库设计和查询优化,可以显著提升查询性能,确保系统的高效稳定运行。
35 9
|
23天前
|
监控 关系型数据库 MySQL
MySQL和SQLSugar百万条数据查询分页优化
在面对百万条数据的查询时,优化MySQL和SQLSugar的分页性能是非常重要的。通过合理使用索引、调整查询语句、使用缓存以及采用高效的分页策略,可以显著提高查询效率。本文介绍的技巧和方法,可以为开发人员在数据处理和查询优化中提供有效的指导,提升系统的性能和用户体验。掌握这些技巧后,您可以在处理海量数据时更加游刃有余。
80 9
|
22天前
|
关系型数据库 MySQL
图解MySQL【日志】——磁盘 I/O 次数过高时优化的办法
当 MySQL 磁盘 I/O 次数过高时,可通过调整参数优化。控制刷盘时机以降低频率:组提交参数 `binlog_group_commit_sync_delay` 和 `binlog_group_commit_sync_no_delay_count` 调整等待时间和事务数量;`sync_binlog=N` 设置 write 和 fsync 频率,`innodb_flush_log_at_trx_commit=2` 使提交时只写入 Redo Log 文件,由 OS 择机持久化,但两者在 OS 崩溃时有丢失数据风险。
38 3
|
1月前
|
存储 缓存 关系型数据库
MySQL原理简介—5.存储模型和数据读写机制
本文介绍了MySQL中InnoDB存储引擎的物理存储结构和读写机制。主要内容包括: 1. 为什么不能直接更新磁盘上的数据 2. 数据页的概念 3. 一行数据的存储 4. 数据头的内容 5. 行溢出和溢出页 6. 数据页的物理结构 7. 表空间的物理结构 8. InnoDB存储模型及读写机制总结 这些机制共同确保了InnoDB在高并发场景下的高效运行和数据一致性。
|
23天前
|
存储 SQL 关系型数据库
【YashanDB 知识库】MySQL 迁移至崖山 char 类型数据自动补空格问题
问题分类】功能使用 【关键字】char,char(1) 【问题描述】MySQL 迁移至崖山环境,字段类型源端和目标端都为 char(2),但应用存储的数据为'0'、'1',此时崖山查询该表字段时会自动补充空格 【问题原因分析】mysql 有 sql_mode 控制,检查是否启用了 PAD_CHAR_TO_FULL_LENGTH SQL 模式。如果启用了这个模式,MySQL 才会保留 CHAR 类型字段的尾随空格,默认没有启动。 #查看sql_mode mysql> SHOW VARIABLES LIKE 'sql_mode'; 【解决/规避方法】与应用确认存储的数据,正确定义数据
|
2月前
|
关系型数据库 MySQL 数据库连接
数据库连接工具连接mysql提示:“Host ‘172.23.0.1‘ is not allowed to connect to this MySQL server“
docker-compose部署mysql8服务后,连接时提示不允许连接问题解决
|
1月前
|
关系型数据库 MySQL 数据库
Docker Compose V2 安装常用数据库MySQL+Mongo
以上内容涵盖了使用 Docker Compose 安装和管理 MySQL 和 MongoDB 的详细步骤,希望对您有所帮助。
175 42

相关产品

  • 云数据库 RDS MySQL 版