数据库中的 Segment、Extent、Page、Row 详解
在关系型数据库的底层存储架构中,数据并不是随意写入磁盘,而是按照一定的结构分层管理的。理解这些存储单位对于优化数据库性能、理解 SQL 执行过程以及排查性能问题都具有重要意义。
我将从宏观到微观,依次介绍数据库存储中的四个核心概念:
- Segment(段)
- Extent(区)
- Page(页)
- Row(行)
1. Segment(段)
Segment 是数据库中用于表示一个完整数据对象(如表、索引等)在磁盘上所占据的所有空间的逻辑集合。
特点:
- 一个 segment 对应一个数据库对象,比如某个表或某个索引。
- 由多个 extent 组成。
- 会随着数据的增加自动扩展(例如 MySQL InnoDB 会自动分配更多 extent)。
- 通常一个 segment 属于一个表空间(tablespace)。
举例:
- 创建一个新表
user
,数据库系统就会为它分配一个 segment。 - 插入数据后,该 segment 会动态增长,向系统请求更多的 extent。
2. Extent(区)
Extent 是一组连续的页(Page),是数据库分配磁盘空间的基本单位。
特点:
- 一般是固定大小(比如 InnoDB 默认是 1MB)。
- 多个 extent 组成一个 segment。
- 避免了频繁地按页分配所带来的碎片问题。
举例(不同数据库的实现可能略有不同):
- MySQL InnoDB:一个 extent 通常由 64 个 16KB 的页组成,即一个 extent 大小为 1MB。
- SQL Server:一个 extent 是 8 个 8KB 页,即 64KB。
3. Page(页)
Page(页) 是数据库中 最小的I/O单位,数据的读取和写入都是以页为单位进行的。
特点:
- 每页固定大小(常见为 8KB、16KB)。
- 一个 extent 中包含若干页。
- 页中除了数据之外,还包含头部(元数据)、行目录等信息。
4. Row(行)
Row(行) 是我们最熟悉的数据单位,即表中的一条记录,最终被存储在页(Page)中。
特点:
- 一页中通常可以存储多行数据。
- 行的格式有固定长度和可变长度两种。
- 若某一行太大,不能完全放入一个页中,系统会使用溢出页或外部存储机制(如 PostgreSQL 的 TOAST、MySQL 的 BLOB)。
优化建议:
- 行长度影响页能装多少行,从而影响索引性能和缓存命中率。
- 尽量避免一行中包含超大字段,建议单独设计表进行拆分。
总结:四者关系图
层级 | 说明 | 示例大小(InnoDB) |
---|---|---|
Segment | 表或索引的所有空间总和 | N/A |
Extent | 一组连续的页 | 1MB(64个16KB页) |
Page | 数据读写的最小单位 | 16KB |
Row | 表中的一条记录 | 变长(数十~数千字节) |