tl;dr: 每个SQLite数据库都是一组文件,其中一个是数据库文件,其他文件用于事务等。在数据库文件中,每个表格都是一个B-tree,每个节点有一行。节点的键是rowid,值是每列的类型和大小,以及该行每列的值。
B-tree的每个节点都是数据库文件中的一个页面。每个页面的大小相同。如果一行太大无法放入页面,则可以溢出到另一页。
SQLite数据库文件格式已有文档记录。它包括两个文件,一个是数据库文件,另一个是回滚日志。回滚日志包含了事务所需的信息。
数据库文件以头部开始,其中包含了关于数据库的编码等信息,并将其余部分分成"页面",即磁盘空间的固定大小块。这使得SQLite能够快速找到文件中特定的内容,而无需读取整个文件,因为它知道文件中每个页面的起始位置,并且可以快速地寻址
到该位置。
它们可以是...
- 锁定字节页(用于Windows强制文件锁定)。
- 空闲页面的链表,例如已删除并准备重用的行。
- 如果一行数据太大而无法放入一页,则会溢出。
- 指针映射,使清理更加高效。
- B-Tree中保存表和索引等内容的页面。
你关心的是最后一个——B-tree。B-tree可以让你存储键值对,查找单个键值对非常快速,按顺序读取整个列表也很快,插入和删除也很快,并且在空间上非常高效。
每个表都是一个散布在页面中的B-tree。树中的每个条目都有一个键,即64位行ID,值为该行。该行表示为标题,描述了该行中每个字段的大小,以及按声明顺序排列的所有列的字节数组。
假设你有:
create table user (
id integer primary key,
name text,
age integer
);
您可以执行
insert into user (name, age) values ("Yarrow Hock", 41)
命令,该命令会获得
id
为12345。它将存储在B树中,其键为12345。值从标题开始,描述列中的内容。
0, 35, 4
0代表整数主键,0表示它为空。由于它是关键字,因此不需要再次存储在值中。
35表示下一个字段是文本,并且长度为11(假设您使用的是UTF-8,您可能正在使用)。这样怎么样?它是(长度* 2)+13
或(11 * 2)+13
。这样做是为了确保该字段始终为奇数,并且超过12个字符。超过12个字符的字段是二进制的。任何小于12的都是整数、浮点数或某些固定宽度的东西。
4表示最后一个字段是32位整数。
最后,所有列的数据被放在一个字节数组中。以下是它在十六进制中的样子。
59 61 72 72 6f 77 20 48 6f 63 6b 00 00 00 29
使用头文件,SQLite知道名称字段从
data [0]
开始,长度为11个字节。那就是
59 61 72 72 6f 77 20 48 6f 63 6b
部分。年龄字段从
data [11]
开始,长度为4个字节,即
00 00 00 29
部分。
所有表、索引、触发器和视图的完整数据库架构存储在一个名为
sqlite_master
的特殊表中,其格式如下。
create table sqlite_master(
type text,
name text,
tbl_name text,
rootpage integer,
sql text
);
它的存储方式与普通表格相同,每个表格、索引、触发器或视图都是一行。
里面还有很多其他的东西,你可以阅读文档以了解更多,但这就是SQLite存储信息的基础知识。我建议你研究B树,它们很棒。