MySQL中的行格式(Row Format)是指存储在数据库表中的数据的物理格式。它决定了数据是如何在磁盘上存储的,以及如何在查询时被读取和解析的。MySQL支持多种行格式,每种格式都有其特定的优点和适用场景。
MySQL被分为Server层和存储引擎层
数据的存储:
在MySQL的生态中,存储引擎很多,但除了Memory存储引擎将数据存储在内存中之外,大多数存储引擎(如常用的InnoDB和MyISAM)都是将数据存储在磁盘上的。
了解这些底层细节对于优化数据库性能、选择合适的存储引擎以及处理大规模数据都是非常有帮助的。
MySQL 的行格式是指表中每一行的存储格式,包括数据、元数据、版本信息、行头等。不同的存储引擎可以支持不同的行格式,例如 InnoDB 存储引擎支持的行格式有 COMPACT、REDUNDANT 和 DYNAMIC 三种。
1. Redundant 行格式:
2. Compact 行格式
3. Dynamic 行格式:
4. Compressed 行格式:
不同行格式对数据读写的影响?
行格式对数据读写效率有显著影响:
行格式的选择
在选择行格式时,需要根据具体的存储需求、硬件资源和性能要求来进行权衡。通常,Compact和Dynamic格式是较为常用的选择,而Redundant格式主要用于与旧版本的MySQL保持兼容,Compressed格式则适用于特定的存储和性能要求。
MySQL版本5.7默认使用DYNAMIC行格式。
指定行格式
你可以在创建或修改表的时候指定行格式。
创建表时指定行格式:
CREATE TABLE mytable (
id INT PRIMARY KEY,
name VARCHAR(100),
data BLOB
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
修改表的行格式:
想改变它的行格式,可以使用 ALTER TABLE 命令:
ALTER TABLE mytable ROW_FORMAT=COMPACT;
查看行格式
要查看表的当前行格式,你可以查询 information_schema 数据库中的 TABLES 表:
SELECT TABLE_NAME, ENGINE, ROW_FORMAT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name';
我们查看ibd文件中 行内容长这样,具体每列代表什么不用特别关注:
1. 变长字段长度列表
2. NULL标志位
3. 记录头信息(record header)
4. 隐藏列
5. 数据字段
之后的部分就是实际存储每个列的数据。
在InnoDB的Dynamic行格式下,处理变长数据类型(如VARCHAR、TEXT和BLOB)的需要存储额外的信息来追踪实际数据的长度,因为这些字段中存储的数据字节数是不固定的:
1. 长度信息的存储:
2. VARCHAR(M)类型:
3. TEXT和BLOB类型:
4. 存储效率:
总的来说,在InnoDB的Dynamic行格式下,变长数据类型通过存储长度信息和可能的页外引用,实现了灵活且高效的数据存储。这种格式特别适合于需要存储大量长文本或二进制数据的应用场景。
六、varchar(M) 能存多少个字符,为什么M提示最大16383?
我们来理解为什么VARCHAR(M)中的M表示字符数,但在实际存储时我们需要考虑字节数。这是因为不同的字符集可能需要不同数量的字节来表示一个字符。例如,在utf8mb4字符集中,一个字符可能需要最多4个字节。
现在,我们来看InnoDB是如何处理VARCHAR字段的
首先,我们需要明白几个关键点:
字符与字节:字符是文本的基本单位,而字节是计算机存储的基本单位。一个字符可能由多个字节组成,这取决于使用的字符集。
utf8mb4字符集:在utf8mb4字符集中,一个字符最多可以占用4个字节。这是因为它支持存储从基本多文种平面到其他辅助平面的所有Unicode字符。
InnoDB的记录结构:InnoDB使用一种复杂的记录结构来存储数据,其中包括用于记录每个变长字段长度的空间。这个空间是有限的,最多使用2个字节来记录一个变长字段的长度。
现在,我们来计算为什么VARCHAR(M)在utf8mb4下最大只能存储约16383个字符:
InnoDB使用2个字节来记录变长字段的长度,这意味着它可以记录的最大长度是2^16 - 1,即65535个字节。
在utf8mb4字符集中,一个字符最多可以占用4个字节。
因此,如果我们想要存储尽可能多的字符,我们需要将65535个字节除以4,得到的结果是16383.75。由于字符数必须是整数,所以最大字符数是16383。
然而,这只是一个理论上的最大值。在实际应用中,由于行中还包括其他信息(如变长字段列表、NULL值列表、记录头信息等),实际可存储的字符数可能会更少。
此外,当字段的数据太大时,InnoDB会将其分成多个部分存储,这称为溢出列。这也意味着即使理论上可以存储16383个字符,实际上也可能达不到这个值。
影响每行实际可用空间的因素有哪些?
VARCHAR(16383) 在理论上应该能够存储 16383 个字符,但在实际应用中可能存不到这么多字符,主要是由于以下几个因素影响了每行实际可用空间:
行格式开销:InnoDB 存储引擎使用特定的行格式(如 Dynamic 或 Compact)来组织数据。每种行格式都有其自身的开销,包括用于存储记录头信息、NULL 值列表、变长字段长度列表等的空间。这些额外的信息会占用行的一部分空间,从而减少可用于实际数据的空间。
记录头信息:每行记录都需要一些额外的字节来存储记录头信息,这些信息包括指向行中各个字段的指针以及记录的其他元数据。
NULL 值列表:如果表中的某些列被定义为允许 NULL 值,并且实际上存储了 NULL 值,那么 InnoDB 需要在行中为每个 NULL 列分配一个额外的字节(在某些情况下,多个 NULL 列可能共享相同的字节,但这取决于具体的行格式和列的数量)。
变长字段长度列表:对于变长字段(如 VARCHAR、TEXT、BLOB),InnoDB 需要在行中存储额外的字节来表示每个字段的实际长度。这个长度前缀通常是 1 或 2 个字节,取决于字段的最大可能长度。
页空间限制:InnoDB 的数据是以页(通常为 16KB)为单位存储的。每页除了存储行数据外,还需要留出空间用于存储页的头信息和尾信息。如果一行数据太大以至于无法完整地放入一个页中,那么它会被分割成多个部分,分别存储在不同的页中。这称为行溢出。
多字节字符集:使用多字节字符集(如 utf8mb4)时,每个字符可能需要多达 4 个字节的存储空间。因此,即使 VARCHAR 字段的长度定义为 16383 个字符,实际存储这些字符所需的字节数也可能远远超过这个数值。
其他列的空间占用:如果表中除了这个 VARCHAR 列之外还有其他列,那么这些列也会占用行的一部分空间,从而减少可用于 VARCHAR 列的空间。
内部碎片和空间复用:InnoDB 可能会在行内留出一些空间以便将来的更新操作,这可能导致一些空间的浪费。此外,由于删除和更新操作,页内可能会留下一些未使用的空间,这些空间可能不会被完全利用。
总的来说,虽然VARCHAR(M)的M值可以很大,但由于多种因素(包括字符集、InnoDB的记录结构和行格式等)的限制,实际可存储的字符数可能会远小于M。
开发规范中不推荐使用NULL,并且倾向于使用NOT NULL约束,这样做有几个好处:
关于NULL值列表的处理过程简要概括一下:
通过这种方式,InnoDB能够高效地存储和检索NULL值信息,尽管这会增加一些额外的存储开销。但是,如果表中的所有列都设置为NOT NULL,那么这个NULL值列表就完全不需要了,从而节省了这部分空间。这也是为什么开发规范中经常推荐尽量避免使用NULL的原因之一。
InnoDB 行溢出是 InnoDB 存储引擎处理行数据过大,无法完全存储在一个数据页(通常是 16KB)中的一种机制。当一行数据的大小超过页内剩余可用空间时,InnoDB 会使用行溢出技术来存储这部分超出的数据。
首先,需要明确的是,InnoDB 的数据是以页为单位进行存储的。每个页除了存储行数据外,还需要存储页的头信息、行目录、最小记录、尾信息等。因此,每个页内实际可用于存储行数据的空间是小于页的大小的。
当一行数据的大小超过了这个可用空间时,InnoDB 会采取以下步骤来处理行溢出:
存储部分数据: InnoDB 首先会尝试将行数据的前 768 字节(这个数字可能会因 InnoDB 的版本和配置而有所不同)存储在数据页内。这部分数据被称为行的“前缀”或“固定部分”。
使用溢出页: 超出的数据部分会被存储在另外的页中,这些页被称为“溢出页”。InnoDB 会在原始数据页内的行记录中保存一个指向溢出页的指针。溢出页中存储了剩余的数据,可以通过数据页内的指针来访问。
动态行格式: 使用行溢出的记录通常会采用动态行格式(DYNAMIC)。在这种格式下,记录的头信息中会包含指向溢出页的指针以及溢出数据的长度等信息。
现在,关于 BLOB 和 VARCHAR 列的数据存储,有几点需要澄清:
BLOB 列: 虽然 BLOB 列通常用于存储大量的二进制数据,但并不意味着 BLOB 列的数据一定会被存储在溢出页中。如果 BLOB 列的数据量很小,并且行的总大小没有超过数据页内的可用空间,那么这些数据仍然会被存储在原始数据页内。
VARCHAR 列: VARCHAR 列虽然通常用于存储较短的字符串,但在某些情况下,如果 VARCHAR 列的数据非常长,并且导致行的总大小超过了数据页内的可用空间,那么 VARCHAR 列的数据也可能被存储在溢出页中。
性能考虑:
Compressed、Dynamic格式对于存放在BLOB中的数据采用了完全的行溢出方式
如下图所示:
总结来说,行溢出不仅仅限于 BLOB 或其他大对象数据类型。任何列的数据,如果导致行的大小超过了数据页内的可用空间,都有可能被存储在溢出页中。InnoDB 通过动态调整数据存储方式,确保了即便在数据量很大的情况下,仍然能够有效地存储和检索数据。
InnoDB行格式是InnoDB存储引擎用来存储表数据的方式。简单来说,InnoDB行格式的原理包括以下几点:
总的来说,InnoDB行格式通过固定与动态存储、行溢出处理和紧凑存储等机制,旨在高效地存储和检索表数据。这些原理保证了InnoDB在处理大量数据时仍然能够保持良好的性能和存储效率。