SQL表数据在磁盘上以“逻辑表→数据页→区→文件→文件组→磁盘”分层存储;数据页为8KB基本单元,含页头、数据区和行偏移数组;连续8页组成区,分混合区与统一区;表数据存于数据文件(.mdf/.ndf),隶属文件组,日志文件(.ldf)独立存放;行存储受压缩、稀疏列、LOB等影响;聚集索引决定数据页物理排序,无则为堆。

SQL 表数据在磁盘上不是以“一张张直观表格”的形式直接存放的,而是通过一套分层、结构化的物理机制组织起来的。核心思路是:逻辑表 → 数据页 → 区(Extent)→ 文件 → 文件组 → 磁盘。
数据页是基本存储单元
SQL Server 中,表数据最终落地为 8KB 大小的数据页(Data Page)。每个页能存多行记录(取决于行宽),但一行不能跨页。页内包含页头(存储元信息)、数据区和行偏移数组(快速定位每行起始位置)。
- 插入新行时,数据库优先找有足够空闲空间的现有页;填满后会分配新页。
- 页按顺序编号,连续 8 个页组成一个 区(Extent),区是空间分配的基本单位。
- 区分混合区(多个对象共享)和统一区(专属一个表或索引),新对象初期用混合区,变大后自动转为统一区。
表与文件的映射关系
表本身是逻辑对象,它实际的数据和索引都保存在 数据文件(.mdf 或 .ndf) 中。这些文件属于某个 文件组(Filegroup) —— 文件组是逻辑容器,用于管理物理文件的分布和权限。
- 默认情况下,表建在 PRIMARY 文件组,对应主数据文件。
- 可手动指定文件组,比如把大表的聚集索引放在高速 SSD 对应的文件组中,提升 I/O 效率。
- 日志文件(.ldf)单独存放事务日志,不存表数据,与数据文件物理分离。
行存储格式依赖数据类型和选项
具体每行怎么写进页里,还受以下影响:
每个应用程序都要使用数据,Android应用程序也不例外,Android使用开源的、与操作系统无关的SQL数据库--SQLite,本文介绍的就是如何为你的Android应用程序创建和操作SQLite数据库。 数据库支持每个应用程序无论大小的生命线,除非你的应用程序只处理简单的数据,那么就需要一个数据库系统存储你的结构化数据,Android使用SQLite数据库,它是一个开源的、支持多操作系统的SQL数据库,在许多领域广泛使用,如Mozilla FireFox就是使用SQLite来存储配置数据的,iPhon
- 行压缩(ROW):去掉固定长度字段的空值占位、缩短数值存储字节(如 int 存 1 时只用 1 字节)。
- 页压缩(PAGE):在行压缩基础上,增加列前缀压缩和页级字典压缩,适合重复值多的宽表。
- 稀疏列(SPARSE):对大量 NULL 的列启用,NULL 几乎不占空间,但非 NULL 值略增开销。
- LOB 数据(如 varchar(max)、xml):若值 ≤ 8000 字节,可能内联存于数据页;超长则存于单独的 LOB 页,数据页中仅保留指针。
聚集索引决定物理排序
如果表有聚集索引(通常是主键),那么数据页本身按索引键顺序链接,形成 B+ 树结构:
- 叶子节点就是实际存数据的页,按键值升序/降序物理排列;
- 非叶子节点只存键值和页指针,用于快速导航。
没有聚集索引的表叫堆(Heap),数据页无特定顺序,靠 IAM(Index Allocation Map)页来跟踪哪些页属于这张表。
不复杂但容易忽略









