Sqlite 技术内幕(译注版)(二)数据库文件格式
1.数据库文件格式在深入到SQLite引擎的细节之前,我首先在以下两小节分别说明一下数据库命名惯例和数据库文件结构。 2.1数据库命名惯例当应用试图通过sqlite3_open API函数打开一个数据库时,都需要传递给该函数数据库文件的名字。文件名可以是参考当前工作目录的相对路径,或者从系统文件树的根结点开始的绝对路径名。所有可以被地文件系统接受的常规文件名都不错。但是,有两个需要注意的例外: l 如果文件名是C语言的空指针(即,0),SQLite会创建并打开一个临时文件 l 如果文件名是”:memory:”,SQLite会创建一个内存数据库 在这两种情况下,当应用关闭数据库连接时,数据库消失,即,数据库不具有持久性 注 SQLite给临时文件命的名是随机的。命名以sqlite_开头,后面接16个数字或者字母组成的字符串。这些文件存储在一个标准的本地临时文件目录。SQLite依次按照(1)/var/tmp、(2)/usr/tmp、(3)/tmp、(4)当前工作目录的顺序,选择临时文件存放的目录。 不管是上述提到的哪种方式打开的数据库(文件、临时数据库或者内存数据库),在SQLite内部都称之(不论已创建与否)为main数据库。 注 在SQLite内部,数据库文件名不是数据库名。SQLite里它们俩是不同但是有关联的概念。通过attach命令,你可以关联同一个数据库文件到一个数据库连接,作为不同的数据库名。你可以通过这些不同的文件名,申请操作这同一个数据库文件。你可以参考SQLite的官网以了解更多关于attach的语义信息。 SQLite为每一个通过sqlite3_open打开的数据库连接维护一个单独的临时数据库。临时数据库存储临时对象,例如表和它们的索引。(应用可以在它们的数据库操作中,使用着两个名字,即main和temp。例如,select * from temp.table1返回temp数据库中table1的所有行,而不是main数据库中。Temp数据库的目录表名是sqlite_temp_master。)临时的对象仅仅在同一个数据库连接中可见(而不是在同一线程、进程或者不同进程连接到同一个数据库文件的其它连接中)。SQLite将temp数据库存放在一个区别于主数据库文件的单独临时文件中。当应用关闭和main数据库的连接时,临时文件将被删除。 2.2数据库文件结构除内存数据库之外,SQLite都会将整个数据库(main或者是temp)存放在单个数据库文件中。 为了方便空间管理和从数据库中读写数据,SQLite将每个数据库(包括内存数据库)划分到固定尺寸的区域。这种区域叫做数据库页,或者简称页。页尺寸是2的指数大小。可以在512到32768之间(也包含这两个边界值);默认值是1024.(在编码和外部存储的多种场合中,存储页尺寸的上限受限于有符号的2字节变量的表示范围。数据库是一个可伸缩的存储页组。存储页组的索引称作页号。页号从1开始,可以增至2,147,483,647(2^32-1)。(上限可能受限于本地操作系统的最大文件尺寸限制。)0号页被当做空页——物理存储上就没有这一页。从文件偏移0的位置开始,1号页和后续页一页接一页存在数据库文件中。 注: 一旦数据库文件被创建,SQLite使用编译时默认尺寸,但是在数据库中创建第一个表之前,尺寸可以通过pragma命令改变。SQLite存储的该尺寸值被当做元数据的一部分。它将使用该尺寸值代替默认值。(前面提到过,pragma命令被用作修改SQLite库的行为。详情参看SQLite的官网。) 有四种类型的存储页:叶子页、内部页、溢出页和空白页。空白页是非活动(当前未被使用)页;其他的都是活动页。B+树的内部页包含搜索的导航信息(B-树内部页有搜索辅助信息和实际数据)。B+树的叶子页存储实际数据(例如,表中的一行行数据)。如果一行的数据太大,一页容不下,一部分就存在树上的页里,另一部分就存在溢出页里。 SQLite可以为任何页类型分配任意数据库页,除了1号页,永远是B+树的内部页。这一页在偏移为0的位置,也保存着一个100字节的文件头记录。头信息描述了数据库文件的结构特征。当创建文件时,SQLite初始化头信息。文件头的格式如下表所述。头两列的单位是字节。 表2-1 数据库文件头结构 |