MySQL中怎么存放一条记录

2.2.1. MySQL中一行记录是怎么存储的?

MySQL的数据存储在那个文件?

每创建一个 database(数据库)都会在 /var/lib/mysql/ 目录里面创建一个以 database 为名的目录,然后保存表结构和表数据的文件都会存放在这个目录里。

在数据库目录中包含三个文件: 

  •  db.opt:存储当前数据库的默认字符集和字符校验规则
    • 表名.ibd:存储表数据,也称为独占表空间文件,每张表都有独立的.ibd文件。
    • 表名.firm:存储表结构,每建立一张表都生成一个.firm文件

表空间文件的结构:

表空间由段(segment)、区(extent)、页(page)、行(row)组成

  1. 行(row)

表中的记录都是按行存放,每行记录根据不同的行格式,有不同的存储结构

  1. 页(page)

InnoDB 的数据是按「页」为单位来读写的,每个页默认空间大小是16kb,是InnoDB 存储引擎磁盘管理的最小单元,常见的有数据页、undo 日志页、溢出页等等,行记录是用数据页管理的。

  1. 区(extent)

B+ 树中每一层都是通过双向链表连接的,以页为单位来分配存储空间,链表中相邻的两个页之间的物理位置并不连续,磁盘查询时就会有大量的随机I/O,随机 I/O 是非常慢的。当表中数据量大时,不再以页为单位给索引分配空间,而是按照区。每个区大小为1MB,连续的64的页会被划分为一个区,使链表中相邻的页的物理位置也相邻,就能使用顺序 I/O 了。

  1. 段(segment)

表空间由各个段组成,段由多个区组成。段一般分为数据段、索引段、和回滚段等。

      • 索引段:存放 B + 树的非叶子节点的区的集合;
      • 数据段:存放 B + 树的叶子节点的区的集合;
      • 回滚段:存放的是回滚数据的区的集合。

InnoDB 行格式有哪些?

行格式(row_format),是一条记录的存储结构。

InnoDB 提供了 4 种行格式,分别是 Redundant、Compact、Dynamic和 Compressed 行格式。

      • Redundant 古老的行格式, MySQL 5.0 版本之前用的行格式,现在基本没人用了。
      • MySQL 5.0 之后引入了 Compact, 是一种紧凑的行格式,为了让一个数据页中可以存放更多的行记录,从 MySQL 5.1 版本之后,行格式默认设置成 Compact。
      • Dynamic 和 Compressed 两个都是紧凑的行格式,它们的行格式都和 Compact 差不多,都是基于 Compact 改进一点东西。从 MySQL5.7 版本之后,默认使用 Dynamic 行格式。

COMPACT 行格式长什么样?

一条完整的记录分为「记录的额外信息」和「记录的真实数据」两个部分。

记录的额外信息:

  1. 变长字段长度列表:

存放记录的真实数据占用的大小,读取时根据「变长字段长度列表」读取对应长度的数据,其他变长字段同理。

用一个实例来进行说明:

CREATE TABLE `t_user` (`id` int(11) NOT NULL,`name` VARCHAR(20) DEFAULT NULL,`phone` VARCHAR(20) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE-- 字符集是 ascii(所以每一个字符占用的 1 字节)
) ENGINE = InnoDB DEFAULT CHARACTER SET = ascii ROW_FORMAT = COMPACT;-- 例如,表中有3条记录
+-------------+-------------+-------------------+-------------------+
|  					id| 			 name | 						phone | 							age |
+-------------+-------------+-------------------+-------------------+
|           1 |           a |               123 |                18 |
+-------------+-------------+-------------------+-------------------+
|           2 |          bb |              1234 |              NULL |
+-------------+-------------+-------------------+-------------------+
|           3 |         ccc |              NULL |              NULL |
+-------------+-------------+-------------------+-------------------+
    • 第一条记录:

name字段的值是a,真实数据占用1字节。phone字段的值是123,真实数据占用3字节。age和id不是变长字段。

这些变长字段的真实数据占用的字节数会按照字段的顺序逆序存放。

    • 第三条记录:phone字段是NULL,NULL 不会存放在行格式中记录的真实数据。

为什么「变长字段长度列表」的信息要按照逆序存放?

因为「记录头信息」中指向下一个记录的指针,指向的是下一条记录的「记录头信息」和「真实数据」之间的位置,这样的好处是向左读就是记录头信息,向右读就是真实数据,比较方便。

还可以使位置靠前的 记录的真实数据和数据对应的字段长度信息可以同时在一个 CPU Cache Line 中,这样就可以提高 CPU Cache 的命中率

同样的道理, NULL 值列表的信息也需要逆序存放。

  1. NULL值列表

就是用来存储NULL值的,每个允许NULL值的字段对应一个二进制位,按照字段的顺序逆序排列。二进制位的值是1时,表示该字段是NULL,为0表示不为NULL。NULL值列表必须整数个字节表示,使用的二进制位数不够整个字节,在字节高位补0。

根据三条记录来看NULL值怎么存储的

    • 第一条记录,没有NULL值,用整数字节的二进制位表示NULL,不足8位高位补0。

    • 第二条记录,age字段是NULL,NULL值列表十六进制表示就是0x04。

    • 第三条记录,phone和age字段都是NULL值,NULL值列表十六进制表示就是0x06。

三条记录NULL值列表填充完成后:

每个数据库表的行格式都有「NULL 值列表」吗?

不是,所有字段都是NOT NULL的时候就不会有NULL值列表了,都设置为NOT NULL还能节省至少1字节的存储空间。

  1. 记录头信息

记录头信息中包含的内容很多,列举几个比较重要的:

  • delete_mask :标识此条数据是否被删除。执行 detele 删除记录的时候,并不会真正的删除记录,只是将这个记录的 delete_mask 标记为 1。
  • next_record:下一条记录的位置。记录与记录之间是通过链表组织的。指向的是下一条记录的「记录头信息」和「真实数据」之间的位置。
  • record_type:表示当前记录的类型,0表示普通记录,1表示B+树非叶子节点记录,2表示最小记录,3表示最大记录。

记录的真实数据:

除了自己定义的字段,还有三个隐藏字段,分别为:row_id、trx_id、roll_pointer。

  • row_id:建表的时候指定了主键或者唯一约束列,就没有 row_id 隐藏字段了。如果既没有指定主键,又没有唯一约束, InnoDB 就会为记录添加 row_id 隐藏字段。row_id不是必需的,占用 6 个字节。

  • trx_id:事务id,表示这个数据是由哪个事务生成的。 trx_id是必需的,占用 6 个字节。

  • roll_pointer:记录上一个版本的指针。roll_pointer 是必需的,占用 7 个字节。

VARCHAR()的最大取值范围是多少?

除了 TEXT、BLOB 类型的字段,限制最大为 65535 字节,注意是一行的总长度,不是一列。

要算 varchar(n) 最大能允许存储的字节数,要看数据库表的字符集,不同的字符集,1个字符占用字节不同,比如 ascii 字符集, 1 个字符占用 1 字节, varchar(100) 最大能允许存储 100 字节的数据。

65535个字节中是包含了「变长字段长度列表」和 「NULL 值列表」所占用字节数的,变长字段存储的字节数小于255字节占用1个字节,如果大于255字节占用两个字节。

计算VARCHAR(n)的最大值需要减去「变长字段长度列表」和 「NULL 值列表」所占用的字节数的,

65535-2-1=65532。

在 UTF-8 字符集下,一个字符最多需要三个字节,varchar(n) 的 n 最大取值就是 65532/3 = 21844。

行溢出后,MySQL是怎么处理的?

MySQL 中磁盘和内存交互的基本单位是页,一个页的大小一般是 16KB,也就是 16384字节,一个 varchar(n) 类型的列最多可以存储 65532字节,一些大对象如 TEXT、BLOB 可能存储更多的数据,这时一个页可能就存不了一条记录。这个时候就会发生行溢出,多的数据就会存到另外的「溢出页」中

一个页存不下一条记录,记录的真实数据处存放部分数据,然后有20个字节存放溢出页的地址,剩余部分存到溢出页中。

Compressed 和 Dynamic采用完全溢出方式,有数据溢出时,记录的真实数据处只存放20字节的指针,指向溢出页,真实数据都存放在溢出页中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/660386.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark SQL编程初级实践

参考链接 Spark编程: Spark SQL基本操作 2020.11.01_df.agg("age"->"avg")-CSDN博客 RDD编程初级实践-CSDN博客 Spark和Hadoop的安装-CSDN博客 1. Spark SQL基本操作 { "id":1 , "name":" Ella" , "age":…

MySql-日期分组

一、分别统计各时间各类型数据条数 数据库的 request_time字段 数据类型:timestamp 默认值:CURRENT_TIMESTAMP 例子: 2024-01-26 08:25:48 原数据: 1、将数据按照日期(年月日)形式输出 按照request_…

RISC和CISC含义及其区别

一、含义 RISC(Reduced Instruction Set Computer)和CISC(Complex Instruction Set Computer)是两种不同类型的计算机架构。它们的区别主要在于指令集和执行时间。 RISC架构通常采用简化的指令集,每条指令执行的操作非…

智能私信软件:转化率提升的神器

在数字化营销领域,利用智能私信软件策略提升转化率已经成为一种不可忽视的趋势。随着人工智能技术的发展,这些软件变得越来越智能,能够根据用户的行为和偏好提供个性化的沟通体验。在这篇文章中,我们将探讨如何有效地运用智能私信…

CSS 06

精灵图 为什么要使用精灵图 一个网页中往往会应用很多小的背景图像作为修饰,当网页中的图像过多时,服务器就会频繁地接收和发送请求图片,造成服务器请求压力过大,这将大大降低页面的加载速度,因此,为了有效地减少服务…

使用 langchain 连接 通义千问 并用 fastApi 开放接口

安装 langchain 方法 https://www.cnblogs.com/hailexuexi/p/18087602 安装 fastapi fastapi 是一个用于构建高性能 Web 应用的 Python 框架,它提供了简洁、高效的 API 开发体验。 pip install fastapi 安装 uvicorn uvicorn 是一个用于运行 FastAPI 应用的服务…

Linux 权限的简单讲解

1、前言 当我们分别使用 touch、mkdir 命令创建一名为 test1 的文件和名为 test2 的目录,发现其中有些参数不一样,本文就来给大家来剖析一下。 2、 参数讲解 我们可以通过切片分为下面几个区域,本文就只简单讲解文件类型、权限、所属用户、所…

【Linux】体系结构和进程管理

目录 一、认识冯诺依曼体系结构 1.1 概念 1.2 组成 1.3 存储分级 1.4 有关冯诺依曼的问题 二、操作系统 2.1 概念和功能 2.2 如何理解操作系统的 "管理" 2.3 操作系统的用户、系统调用和库函数概念 三、进程 3.1 基本概念 3.2 描述进程-进程控制块PCB …

基于python的舞蹈经验分享交流网站django+vue

1.运行环境:python3.7/python3.8。 2.IDE环境:pycharmmysql5.7/8.0; 3.数据库工具:Navicat11 4.硬件环境:windows11/10 8G内存以上 5.数据库:MySql 5.7/8.0版本; 运行成功后,在浏览器中输入&am…

UE4 Widget制作搜索框

效果: 一、控件层级结构 1.父控件层级结构 2.子控件层级结构 二、蓝图 1.先清除掉创建子项(注意:这里使用的是reverse循环!) 2.判断是否含有关键字,创建子控件

ElasticSearch总结2

一、创建索引库:PUT ES中通过Restful请求操作索引库、文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下: 整个jason 里边,它有一个叫mapping的属性,代表的是映射。映射里边有properties代表就是字段。可以看到这…

W801学习笔记十二:掌机进阶V3版本之驱动(PSRAM/SD卡)

本次升级添加了两个模块,现在要把他们驱动起来。 一:PSRAM 使用SDK自带的驱动,我们只需要写一个初始化函数,并在其中添加一些自检代码。 void psram_heap_init(){wm_psram_config(0);//实际使用的psram管脚选择0或者1&#xff…