SQLite版本:3.14.1
SQLite数据库文件由多个页面组成,每个页面的大小相同。这方便了程序读取页面。
首页面结构如下:
文件头 |
大小为100个字节。只有首页面有文件头。 |
页面头 |
大小为8个字符,或12个字节。 |
Cell指针数组 |
每个cell数组元素大小为2个字节。按顺序存储。下页面底部增长。 |
未分配空间 |
|
Cell内容区域 |
由页面底部向上增长。 |
** OFFSET SIZE DESCRIPTION
** 0 16 Header string: "SQLite format 3\000"
** 16 2 Page size in bytes. (1 means 65536)
** 18 1 File format write version
** 19 1 File format read version
** 20 1 Bytes of unused space at the end of each page
** 21 1 Max embedded payload fraction (must be 64)
** 22 1 Min embedded payload fraction (must be 32)
** 23 1 Min leaf payload fraction (must be 32)
** 24 4 File change counter
** 28 4 Reserved for future use
** 32 4 First freelist page
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
**
** 40 4 Schema cookie
** 44 4 File format of schema layer
** 48 4 Size of page cache
** 52 4 Largest root-page (auto/incr_vacuum)
** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
** 60 4 User version
** 64 4 Incremental vacuum mode
** 68 4 Application-ID
** 72 20 unused
** 92 4 The version-valid-for number
** 96 4 SQLITE_VERSION_NUMBER
其中Page size字符指定了页面大小。
目前,只分析BTree页面。
BTree页面的页面头结构如下:
偏移量 |
大小 |
描述 |
0 |
1 |
在偏移量为0处的flag,大小为一个字节。此flag表示一个b-tree页面类型。 Flag=2(0x02),页面类型为内部索引b-tree页面(interior index b-tree page) Flag=2(0x05),页面类型为内部表格b-tree页面(interior table b-tree page) Flag=10(0x0a),页面类型为叶子索引b-tree页面(leaf index b-tree page) Flag=13(0x0d),,页面类型为叶子表格b-tree页面(leaf table b-tree page) |
1 |
2 |
在偏移量为1处的flag,大小为二个字节,类型为整数。它指定在此页中,freelock的开始的地方。或者是0,如果没有freeblock。 |
3 |
2 |
在偏移量为3处的num,大小为二个字节,类型为整数。此num为在此页中cell的数量。 |
5 |
2 |
在偏移量为3处的num,大小为二个字节,类型为整数。此数值指定了cell内容区域开始的地方官。如果是0,则被解释为65536。 |
7 |
1 |
在偏移量为7处的数值,大小为一个字节。它为此页中fragmente free bytes的数量。 |
8 |
4 |
The four-byte page number at offset 8 is the right-most pointer. 此值只在interior b-tree页的头中显示,其它种类的页面中无意义。 |
四种B-Tree对应四种不同的Cell格式,这里只介绍leaf table b-tree page的Cell结构。其结构如下:
以varint表示的payload的总字节数 |
包含溢出的字节数。字符数类型为varint。Payload即是保存的数据。此变量为保存数据的大小。 |
以varint表示的整数键值 |
例如”rowid”。 |
payload的初始化区域 |
不包含分割到溢出页中的payload。即保存数据的地方。 |
溢出页面编号 |
一个大端存储的4字节整数。此整数为溢出页面链表中第一个页面的编号。如果所有的payload填满了此b-tree page,则忽略。 |
Varint类型
SQLite中整数键值为64位整数,某些保存长度的变量的类型也为64位整数。64位整数要占8个字节。但在整数值大部分情况下都较小,用不上64位。所以,SQLite使用Huffman编码压缩保存64位整数。压缩后的长度在1到9个字节之间。
CREATE TABLE company
(
id int primary key not null,
name text not null,
age int not null,
address char(50),
salary real);
INSERT INTO "company" VALUES(1,'Paul',32,'California',20000.0);
INSERT INTO "company" VALUES(2,'Allen',25,'Texas',15000.0);
青绿色部分为文件头部分。橙色+蓝色部分为一个cell。橙色部分为:以varint表示的payload的总字节数+以varint表示的整数键值。蓝色部分为payload的初始化区域。
Pager.c文件中的readDbPage函数,从磁盘读入一个页。Bree.c文件中的btreeParseCellPtr函数,解析类型为leaf table b-tree page的cell。