主要參考:
- 1惹谐、《SQLite數(shù)據(jù)庫文件格式全面分析.doc 》碾篡,鏈接不詳,只是能再網(wǎng)上各個文庫上找到此文檔蹂喻。
- 2延赌、官網(wǎng)文檔 Database File Format
前提準(zhǔn)備
準(zhǔn)備好文件
在win10環(huán)境下
PS G:\code-2\sqlite3> ./sqlite3 small.db
SQLite version 3.28.0 2019-04-16 19:49:53
Enter ".help" for usage hints.
sqlite> CREATE TABLE department(id int, dept char(30), emp_id int);
sqlite> insert into department values(1, "test", -1);
sqlite> insert into department values(2, "test", 1);
sqlite> .qu
準(zhǔn)備一些小工具
從sqlite官網(wǎng)下載的源碼中的tool
目錄中有一些十分有用的小工具,例如showdb
叉橱、showwal
等挫以,它們都是單個源文件組成,結(jié)合官網(wǎng)提供的sqlite-amalgamation-xxx.zip
提供的sqlite3.h
和sqlite3.c
就可以編譯出來窃祝。例如showdb
是由showdb.c
編譯出來的:gcc -g -O0 -o showdb showdb.c sqlite3.c
掐松,調(diào)試和編譯優(yōu)化選項看個人喜歡,可加可不加粪小。
最最基礎(chǔ)的概念
首先要明白三點:
- sqlite3數(shù)據(jù)庫是由單個文件組成的大磺,而這個文件被稱為主數(shù)據(jù)庫文件
main database file
。這個文件又是由多個頁page
組成探膊,頁按順序編號杠愧,從1開始。sqlite上層的b樹最小組成單位就是頁逞壁,至于如何存儲流济,如何查找等我寫完就差不多弄清楚了锐锣。還有頁的分類都是后話,所有底層設(shè)計都是為了上層服務(wù)的绳瘟,個人理解的時候要會把握關(guān)鍵的思路雕憔,再慢慢理順細(xì)節(jié)。 - 存儲在文件中的數(shù)據(jù)格式全部都是大端格式糖声,為什么是大端呢斤彼?不清楚,就像網(wǎng)絡(luò)字節(jié)序也是用大端存儲蘸泻,不過大端存儲在調(diào)式的時候有個明顯的優(yōu)勢就是符合人類閱讀習(xí)慣琉苇。
-
sqlite_schema
是一個特殊的表(別名有很多,例如sqlite_master)悦施,它存放著其余表對應(yīng)所在的根頁號翁潘,具體定義如下:
CREATE TABLE sqlite_schema(
type text,
name text,
tbl_name text,
rootpage integer,
sql text
);
開始分析這個小文件
文件頭
主數(shù)據(jù)庫文件的前100個字節(jié)即是文件頭。格式官網(wǎng)也給出了:
Offset | Size | Description |
---|---|---|
0 | 16 | The header string: "SQLite format 3\000" |
16 | 2 | The database page size in bytes. Must be a power of two between 512 and 32768 inclusive, or the value 1 representing a page size of 65536. |
18 | 1 | File format write version. 1 for legacy; 2 for WAL. |
19 | 1 | File format read version. 1 for legacy; 2 for WAL. |
20 | 1 | Bytes of unused "reserved" space at the end of each page. Usually 0. |
21 | 1 | Maximum embedded payload fraction. Must be 64. |
22 | 1 | Minimum embedded payload fraction. Must be 32. |
23 | 1 | Leaf payload fraction. Must be 32. |
24 | 4 | File change counter. |
28 | 4 | Size of the database file in pages. The "in-header database size". |
32 | 4 | Page number of the first freelist trunk page. |
36 | 4 | Total number of freelist pages. |
40 | 4 | The schema cookie. |
44 | 4 | The schema format number. Supported schema formats are 1, 2, 3, and 4. |
48 | 4 | Default page cache size. |
52 | 4 | The page number of the largest root b-tree page when in auto-vacuum or incremental-vacuum modes, or zero otherwise. |
56 | 4 | The database text encoding. A value of 1 means UTF-8. A value of 2 means UTF-16le. A value of 3 means UTF-16be. |
60 | 4 | The "user version" as read and set by the user_version pragma. |
64 | 4 | True (non-zero) for incremental-vacuum mode. False (zero) otherwise. |
68 | 4 | The "Application ID" set by PRAGMA application_id. |
72 | 20 | Reserved for expansion. Must be zero. |
92 | 4 | The version-valid-for number. |
96 | 4 | SQLITE_VERSION_NUMBER |
對應(yīng)的小文件分析可以用showdb可知:
PS G:\code-2\sqlite3> ./showdb small.db dbheader
Pagesize: 4096
Available pages: 1..2
000: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
010: 10 00 01 01 00 40 20 20 00 00 00 03 00 00 00 02 .....@ ........
020: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
030: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
060: 00 2e 34 20 00 ..4 .
Decoded:
010: 10 00 4096 Database page size
012: 01 1 File format write version
013: 01 1 File format read version
014: 00 0 Reserved space at end of page
018: 00 00 00 03 3 File change counter
01c: 00 00 00 02 2 Size of database in pages
020: 00 00 00 00 0 Page number of first freelist page
024: 00 00 00 00 0 Number of freelist pages
028: 00 00 00 01 1 Schema cookie
02c: 00 00 00 04 4 Schema format version
030: 00 00 00 00 0 Default page cache size
034: 00 00 00 00 0 Largest auto-vac root page
038: 00 00 00 01 1 Text encoding
03c: 00 00 00 00 0 User version
040: 00 00 00 00 0 Incremental-vacuum mode
044: 00 00 00 00 0 Application ID
048: 00 00 00 00 0 meta[8]
04c: 00 00 00 00 0 meta[9]
050: 00 00 00 00 0 meta[10]
054: 00 00 00 00 0 meta[11]
058: 00 00 00 00 0 meta[12]
05c: 00 00 00 03 3 Change counter for version number
060: 00 2e 34 20 3028000 SQLite version number
頁大小 (Database page size)
在0x10偏移處歼争,規(guī)定了頁的大小,取值必須是2的冪次方渗勘,范圍為[512, 65536]
沐绒,這里有點小細(xì)節(jié)可以參考官網(wǎng)文檔可知。
文件格式版本(File format write/read version)
現(xiàn)在僅存在1和2兩種旺坠,分別代表Hot journal
和WAL journal
乔遮。小文件分析時候采用的是前者。
頁的保留空間大小 (Reserved space at end of page)
保留空間是在頁的尾部開始取刃,其的用途例如在加密插件啟用的時候蹋肮,存儲nonce
值或者頁面的校驗和。一般來說這個字段一般為0璧疗。
Payload Fraction
0x21-23是連續(xù)的頁內(nèi)每個單元占用的百分比坯辩,以255為分母,這三個值64\32\32分別做分子崩侠,可得到對應(yīng)的百分比25%漆魔,12.5%,12.5%却音。前兩個是給index使用的改抡,分別表示最大和最小值,后一個是給table b-tree leaf page的最小值系瓢,其最大值是是pagesize - 35
文件修改次數(shù)計數(shù)器(File change counter)
統(tǒng)計每一次修改數(shù)據(jù)庫文件阿纤,到目前為止,我們先是創(chuàng)建表一次夷陋,兩次獨立(相當(dāng)于兩次事務(wù))的插入操作欠拾,所以總共修改了文件3次胰锌。
當(dāng)前數(shù)據(jù)庫頁的數(shù)目(Size of database in pages)
字面意思,不過歷史版本上對其處理還是有不一樣的清蚀,這個值會需要進(jìn)一步的和數(shù)據(jù)庫文件大小相比較匕荸,如果不一致則采用具體的數(shù)據(jù)庫文件大小。
空閑頁
這里開始涉及到頁的分類了枷邪,先簡單的理解一下空閑頁榛搔。它的存在是因為數(shù)據(jù)庫在進(jìn)行刪除操作的時候,導(dǎo)致整一頁的數(shù)據(jù)都被清除掉了东揣,此時就要把該頁添加入空閑頁鏈表践惑。
這個鏈表在文件中的存儲方式,是隱式鏈表嘶卧,也就是頁頭會存放著指向下一個空閑頁的下標(biāo)尔觉。而第一個空閑頁則由主數(shù)據(jù)庫文件的文件頭給出。
回到我們的小文件分析芥吟,此時我們的數(shù)據(jù)庫沒有多余的頁侦铜,所以Page number of first freelist page == 0
,0可以理解為c語言中的NULL
钟鸵,并且空閑頁數(shù)目也等于0
Schema cookie
這里的Schema
钉稍,中文翻譯怎么都不太恰當(dāng)。它是整個數(shù)據(jù)庫所有表的總和棺耍,而這cookie則是一個整數(shù)贡未,每次Schema
發(fā)生改動(也就是發(fā)生表的增刪改操作)就自增。這里一個相關(guān)的使用場景就是調(diào)用sqlite3_step
的時候會去檢查schema
是否發(fā)生變化蒙袍。
Schema format number
它代表著schema
不同歷史時期的功能支持程度俊卤,可以見官網(wǎng)描述。這里直接摘抄原文害幅,現(xiàn)在默認(rèn)是用版本4消恍。
- Format 1 is understood by all versions of SQLite back to version 3.0.0 (2004-06-18).
- Format 2 adds the ability of rows within the same table to have a varying number of columns, in order to support the ALTER TABLE ... ADD COLUMN functionality. Support for reading and writing format 2 was added in SQLite version 3.1.3 on 2005-02-20.
- Format 3 adds the ability of extra columns added by ALTER TABLE ... ADD COLUMN to have non-NULL default values. This capability was added in SQLite version 3.1.4 on 2005-03-11.
- Format 4 causes SQLite to respect the DESC keyword on index declarations. (The DESC keyword is ignored in indexes for formats 1, 2, and 3.) Format 4 also adds two new boolean record type values (serial types 8 and 9). Support for format 4 was added in SQLite 3.3.0 on 2006-01-10.
Default page cache size
默認(rèn)的頁緩存大小,只是一個建議以现,實際上由程序自己判斷
Incremental vacuum settings
Largest auto-vac root page
和 Incremental-vacuum mode
都是vacuum
相關(guān)的設(shè)置哺哼,前者是auto_vacuum
模式使用,后者是incremental_vacuum
模式使用叼风。當(dāng)前者等于0時候取董,ptrmap
類型的頁將會被從數(shù)據(jù)庫文件中剔除,并且這兩種模式都不會被支持无宿。當(dāng)前者不為0的時候茵汰,它指向的是最大的根頁,儲存著許多ptrmap
類型的頁孽鸡,并且此時由后者控制是auto_vacuum
還是incremental_vacuum
文本編碼 Text encoding
- 1 for UTF-8
- 2 for UTF16LE
- 3 for UTF16BE
User version
這是給用戶使用的版本號蹂午,sqlite3 并不使用它栏豺。這好像在系統(tǒng)升級的時候確實有用
Application ID
這個也是留給用戶使用的,表示當(dāng)前是由那個進(jìn)程在使用豆胸。這個用處沒這么大奥洼。
sqlite3 庫使用的版本
Change counter for version number
和SQLite version number
,在0x5c和0x60存放的是sqlite3.so/sqlite3.dll在使用此數(shù)據(jù)庫文件時候晚胡,存放的版本號灵奖,并且自增修改次數(shù)。用途不太明確估盘,但是應(yīng)該用來判斷是否有不同版本的sqlite3庫修改此文件吧瓷患。