Inside SQLite 第二章 Database File Format数据库文件格式

第二章  数据库文件格式

在了解SQLite引擎内部细节时,我将在下面两小节首先描述下数据库命名规则和数据库文件结构。

2.1 数据库命名规则
当一个应用程序试图使用sqlite3_open() 函数去打开一个数据库时,是通过给此函数传入“数据库文件名称”作为参数的。这个文件名可以是当前工作路径的相对路径,或者是文件系统的绝对路径。任何能被文件系统识别的正规的文件名都可以。除了以下两种:
a、文件名是c语言中的空指针(NULL)(如:0),SQLite会创建并打开一个新的临时文件;
b、如果文件名是“:memory ”,SQLite创建一个内存数据库。
以上两种情况,当应用程序关闭数据库连接,数据库会被销毁,也就是数据库不是持久的。

注意
SQLite中所有的临时文件名都是随机的,名字都以sqlite_开头加上16位的数字字母组合。这些文件存储在一个标准的本地临时文件目录中。SQLite寻找路径的顺序是: (1)  /var/tmp, (2)  /usr/tmp, (3)  /tmp, (4) 当前工作路径。
上面两种提到的打开的数据库,是SQLite内部数据库——main。

注意
在内部,数据库文件名不是这个数据库名字。这是两个相关又不同的概念。使用SQLite attach命令,你可以把一个相同的数据文件和一个数据库连接联系起来当做不同的数据库名。你可以通过这些数据库名去操作同一个数据库文件。你可以到SQLite官网去 了解更多关于attach的用法。
SQLite包含一个独立的临时数据库(名为temp),这是为保存应用程序用sqlite3_open()打开的每一个数据库连接。这个temp数据库存储临时对象,例如表和索引。(应用程序在查询中可以用这两个名字——main和temp,例如select * from temp.table1 将返回temp数据库中表table1的所有行,而不是从main数据库中,这个temp数据库的目录名/文件名是sqlite_temp_master).临时对象只对相关的数据库连接是可见的(不是同一线程、进程或不同进程中打开相同数据库文件的其他连接)。SQLite在一个独立的临时文件中存储temp数据库,它与main数据库文件是不同的。在应用程序关闭main数据库连接是它将会被删除。

2.2 数据库文件结构

除了内存数据库,SQLite存储整个(main或者temp)数据库在一个独立的文件中。

2.2.1 页
为节省空间和从数据库中读写数据,SQLite为每个数据库(包括内存数据库)提供合适大小的区域,称为“数据库页”,或者简称“页”。页大小是2的幂次,介于512到32768之间,默认值是1024。数据库是(可扩展和可收缩的)一个页的数组。页数组的索引被称为页号。页号从1开始,一直到2,147,483,647 (2 31 – 1)。(上界受限于本地文件系统文件大小的最大值)。页号0被当做“空页”或者说“不是页”——这个页在物理上是不存在的。在数据库文件中从偏移0开始是第一页向后一个接一个的页存储。

注意
一旦数据库文件被创建,SQLite使用编译时的默认页大小,但是大小可以在创建数据库表之前使用编译命令改变。SQLite作为元数据的一部分存储页的大小。它将使用指定页大小代替默认值(就像前面提到的,编译命令用来修改SQLite库的行为,详见SQLite主页)。

2.2.2 页类型
页有四种类型:叶子页(leaf)、内部页(internal)、溢出页(overflow)、空闲页(free)。空闲页是不活跃的(未使用的),其他页都是活跃页。  B+-tree 内部页包含查询时需要的索引信息(B-tree内部页有搜索信息和数据)。在B+-tree中叶子页存储真正的数据(如表的行)。如果一行的数据对一页来说太大,数据的一部分会被存储在树叶,另一部分存储在溢出页中。

2.2.3 文件头
SQLite能使用除了第一页的任何类型的页,第一页是B+-tree的内部页,这个页包含100字节的文件头,存储在文件偏移为0的位置,文件头信息记录了数据库文件的结构。SQLite初始化这个文件头在创建文件的时候。文件头的结构在下表给出。前两列单位是字节。

表2-1. 数据库文件头结构
OffsetSizeDescription
016Header string
162Page size in bytes
181File format write version
191File format read version
201Bytes reserved at the end of each page
211Max embedded payload fraction
221Min embedded payload fraction
231Min leaf payload fraction
244File change counter
284Reserved for future use
324First freelist page
364Number of freelist pages
406015 4-byte meta values

这是每一个元素的详细解释:

Header string

16字节字符串:“SQLite format 3

Page size

页大小

File format

在偏移18、19的两字节用来表示文件格式版本。在目前的SQLite版本中都为1,如果以后文件结构改变了,这些数字会变为新的文件格式版本号。

reserved space

SQLite在每一页的最后预留一个很小的空间(小于255字节),这个值存储在偏移20的位置,默认值是0。当数据库使用加密技术是这个值非零。一个页的第一部分(页大小减去预留的大小)是数据库内容存储的可用空间。

embedded payload

嵌入式系统的有效载荷值的最大值(偏移为21的位置)是一个页中所有可用空间的数量,它可以被一个B/B+tree内部节点的一个单元(single entry)使用。255表示100%,默认最大嵌入式有效载荷值是64(25%)。这个值是为了限制一个单元的最大值,使4个单元适用于一个节点。如果一个单元的有效载荷大于最大值,额外的有效载荷会溢出到溢出页。一旦SQLite分配一个溢出页,它移动尽可能多的字节到溢出页,直到一个单元的值跌到嵌入式有效载荷的最小值(在偏移22的位置)。默认值是32(12.5%)。

The max embedded payload fraction value (at offset 21) is the amount of the total usable space in a page that can be consumed by a single entry (called a cell or record) of a standard B/B+-tree internal node. A value of 255 means 100 percent. The default max embedded payload fraction value is 64 (i.e., 25 percent): the value is to limit the maximum cell size so that at least 4 cells fit on one node. If the payload for a cell is larger than the max value, then extra payload is spilled into overflow pages. Once SQLite allocates an overflow page, it moves as many bytes as possible into the overflow page without letting the cell size to drop below the min embedded payload fraction value (at offset 22). The default value is 32, i.e., 12.5 percent.

The min leaf payload fraction value (at offset 23) is like the min embedded payload fraction, except that it is for B+-tree leaf pages. The default value is 32, i.e., 12.5 percent. The max payload fraction value for a leaf node is always 100 percent (or 255), and is not specified in the header. (There are no special-purpose leaf nodes in B-trees.)

File change counter

文件改变计数器(在偏移24处)用于事务。这个值随着每一次事务增长。这个值用来表示数据库改变以至于pager要避免不得不清除cache,然而这个特征还没有实施在写操作之后,这个pager负责增加这个变量的值。

The file change counter (at offset 24) is used by transactions. That value is incremented by every transaction. This value is intended to indicate when the database has changed so that the pager can avoid having to flush its cache, though that feature has not been implemented as of this writing. The pager is responsible for incrementing this value.


Freelist

没有用的页的空闲链表在文件头的32位移处。空闲页的总数存储在位移36处。这个空闲链组织为一个有根的树结构。空闲链表中的页有两种:树页(trunk pages)和叶子页(leaf pages)。这个文件头指向这个链的第一个树页。每一个树页(trunk page)指向多个叶子页(leaf page),每一个叶子页内容未指明。

表2-1. 空闲链结构


一个树页格式如下,从页底部开始:
a、一个下一个树页的4字节页号
b、一个4字节整数来表示这个树页存储的叶子页指针的个数、
c、0或更多4字节叶子页的个数
当一个页变得不活跃,SQLite增加它到空闲链表,而不是释放它到本地文件系统。当你增加新的信息到数据库时,SQLite拿出空闲链表中的空闲页来存储信息。如果空闲链表空了,SQLite从文件系统获得新页,然后增加到数据库文件。

注意
你可以使用命令行vacuum来清空数据库中的空闲链表。这个命令复制一个数据库到一个临时文件(复制过程使用INSERT INTO,SELECT * FROM...等命令)。然后它用临时复制的这个文件重写了原始的数据库,在一个事务的保护下。
Meta variables
在位移40处,有15个4字节整数是为B + -tree和VM(虚拟机)模块预留。他们表示很多元数据变量的值,包括位移40处的数据库模式 cookie 数( database schema cookie number ),这个值在每次模式改变的时候增加。其他元数据变量包括在位移44处的模式层( the schema layer )的文件格式信息,48位移出的页缓存大小,52位移处的系统自动清除进程标识(autovacuum  flag ) ,56位移处文本编码(1:UTF-8, 3:UTF-16 LE, 4:UTF-16 BE),60位移处用户版本号。你可以找到更多变量在SQLite源文件btree.c中。

注意
SQLite数据库文件格式是向下兼容的,从版本3.0.0开始。这意味着SQLite的任何版本可以读写被3.0.0版本SQLite创建的数据库文件。还有就是版本3.0.0 SQLite可以读写任何版本的SQLite库创建的数据库。然而,在新版本的SQLite中有一些新的特性,版本3.0.0不能识别的,如果数据库包含这些新特性的信息,老版本的库将不能读和识别它。
在页号为1的页中,文件头后面是B + -tree的内部节点。这个节点是主目录表( the master catalog table )的根节点,表名是 sqlite_master  或者 sqlite_temp_master, 分别 存储在一个正规的数据库(main数据库或attached数据库)或temp数据库。

注意
所有多字节整数值采用大端存储顺序。这保证你可以移动你的数据库文件从一个平台移动到另一个。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值