# 第1章? SQLite介紹
SQLite是一個開源的、內嵌式的關系型數據庫。它最初發布于2000年,在便攜性、易用性、緊湊性、有效性和可靠性方面有突出的表現。
## 內嵌式數據庫
SQLite是一個內嵌式的數據庫。
數據庫服務器就在你的程序中,其好處是不需要網絡配置和管理。數據庫的服務器和客戶端運行在同一個進程中。這樣可以減少網絡訪問的消耗,簡化數據庫管理,使你的程序部署起來更容易。所有需要你做的都已經和你的程序一起編譯好了。
如圖1-1所示。一個Perl腳本、一個標準C/C++程序和一個使用PHP編寫的Apache進程都使用SQLite。Perl腳本導入DBI::SQLite模板,并通過它來訪問C API。PHP采用與C相似的方式訪問C API。總之,它們都需要訪問C API。盡管它們每個進程中都有獨立的數據庫服務器,但它們可以操作相同的數據庫文件。SQLite利用操作系統功能來完成數據的同步和加鎖。

圖1-1 內嵌的主進程中的SQLite
目前市場上有多種為內嵌應用所設計的關系型數據庫產品,如Sybase SQL Anywhere、InterSystems Caché、Pervasive PSQL和微軟的Jet Engine。有些廠家從他們的大型數據庫產品翻新出內嵌式的變種,如IBM的DB2 Everyplace、Oracle的10g和微軟的SQL Server Desktop Engine。開源的數據庫MySQL和Firebird都提供內嵌式的版本。在所有這些產品中,僅有兩個是完全開放源代碼的且不收許可證費用——Firebird和SQLite。在這兩個當中,僅有一個是專門為內嵌式應用設計的——SQLite。
## 開發者的數據庫
SQLite具有多方面的特性。它是一個數據庫,一個程序庫,一個命令行工具,也是一個學習關系型數據庫的很好的工具。確實有很多途徑可以使用它——內嵌環境、網站、操作系統服務、腳本語言和應用程序。對于程序員來說,SQLite就象一個數據傳送帶,提供了一種方便的將應用程序綁定的數據的方法。就象傳送帶一樣,對SQLite的使用沒有終點。
除了僅僅作為一個存儲容器,SQLite還可以作為一個單純的數據處理的工具。如果大小和復雜性合適,使用SQLite可以很容易地將應用程序所使用的數據結構轉化為表,并保存在一個內在數據庫中。用此方法,你可以操作互相關聯的數據,可以完成很繁重的任務頁不必寫自己的算法來對數據結構操作和排序。如果你是一個程序員,想像一下在你的程序中自行完成下面SQL語句所代表的工作需要多少代碼:
```
SELECT AVG(z-y) FROM table GROUP BY x
??? HAVING x > MIN(z) OR x < MAX(y)
??? ORDER BY y DESC LIMIT 10 OFFSET 3;
```
SQLite還是一個很好的學習程序設計的工具,通過它可以研究很多計算機科學的課題。分析器、分詞器、虛擬機、Btree算法、高整緩存、程序體系結構,通過這些內容可以搞清楚很多計算機科學的經典概念。SQLite的模塊化、小型化和簡易性,使你可以很容易地專門研究其中的一個問題。
## 管理員的數據庫
SQLite不僅是程序員的數據庫,它對系統管理員也很有用。它很小、緊湊而精致,就像一些Unix的常用工具,如find、rsync或grep。SQLite提供了命令行工具供用戶交互操作。
另外,對于關系型數據庫的初學者來說,SQLite是一個學習各種關系相關概念的方便的學習工具。它可以很快很容易地安裝在各類操作系統中,它的數據庫文件可以自由共享頁不需要任何轉換。它具有關系型數據庫的各種特色而又不令人生畏。它的程序和數據庫文件僅用U盤就能傳遞。
## SQLite 的歷史
從某個角度來說,SQLite最初的構思是在一條軍艦上進行的。SQLite的作者D. Richard Hipp當時正在為美國海軍編制一種使用在導彈驅逐艦上的程序。那個程序最初是運行在Hewlett-Packard Unix (HPUX)上,后臺使用Informix數據庫。對那個程序來說,Informix有點兒太強大了。一個有經驗的數據庫管理員(DBA)可能需要一整天來對它進行安裝和升級,如果沒經驗,這個工作就可能永遠也做不完了。
2000年一月,Hipp開始和一個同事討論關于創建一個簡單的內嵌式SQL數據庫的想法,這個數據庫將使用GNU DBM B-Tree library (gdbm)做后臺,同時這個數據庫將不需要安裝和管理支持。后來,當有些空閑時間時,Hipp就開始實施這項工作,并在2000年的八月份發布了SQLite的1.0版。
按照原定計劃,SQLite 1.0用gdbm來做存儲管理。但后來,Hipp很快就換成了自己的B-tree,以支持事務和記錄按主鍵的存儲。隨著最初的升級,SQLite在功能和用戶數上都得到了穩步的發展。在2001年中期,很多項目——開源的或商業的——都開始使用SQLite。在那以后的幾年中,開源社區的其他成員開始為他們喜歡的程序設計語言編寫SQLite擴展。SQLite的ODBC接口可以為Perl、Python、Ruby、Java和其它主流的程序設計語言提供支持,這證明了SQLite有廣闊的應用前景。
2004年,SQLite從版本2升級到版本3,這是一次大升級。主要目的是增加內置的對UTF-8、UTF-16及用戶定義字符集的支持。While 3.0 was originally slated for release in summer 2005, America Online provided the necessary funding to see that it was completed by July 2004\. 除國際化功能外,版本3的其它新特性包括:經過修補的C API,更緊湊的數據庫文件格式(比原來節省25%的空間),弱類型,大二進制對象(BLOB)的支持,64-bit的ROWID,autovacuum和改進了的并發控制。盡管增加了這一系列新特性,版本3的運行庫仍然小于240K字節。Another improvement in version 3 was a good code cleanup—revisiting and rewriting, or otherwise throwing out extraneous stuff accumulated in the 2.x series.
SQLite持續增長并始終堅持其最初的設計目標:簡單、彈性、緊湊、速度和徹底的易用。本書出版時,SQLite已經增加了CHECK約束,下面就要增加外鍵約束,再下面呢?
## 誰使用SQLite?
當前,SQLite已經被多種軟件和產品所使用。它被用在Apple的Mac OS X操作系統中,被用作其CoreData應用程序架構的一部分。它還應用于Safari的Web瀏覽器、Mail.app的電子郵件程序、RSS的管理、Apple的Aperture照片軟件。
盡管SQLite很少做廣告,但它還是被用在了多種消費類產品中。
## 體系結構
SQLite擁有一個精致的、模塊化的體系結構,并引進了一些獨特的方法進行關系型數據庫的管理。它由被組織在3個子系統中的8個獨立的模塊組成,如圖1-2所示。這個模型將查詢過程劃分為幾個不連續的任務,就像在流水線上工作一樣。在體系結構棧的頂部編譯查詢語句,在中部執行它,在底部處理操作系統的存儲和接口。

圖1-2 SQLite的體系結構
## 接口(Interface)?
接口由SQLite C API組成,也就是說不管是程序、腳本語言還是庫文件,最終都是通過它與SQLite交互的(我們經常使用的ODBC/JDBC最后也會轉化為相應C API的調用)。
## 編譯器(Compiler)
編譯過程從分詞器(Tokenizer)和分析器(Parser)開始。它們協作處理文本形式的結構化查詢(Structured Query Language, SQL)語句,分析其語法有效性,轉化為底層能更方便處理的層次數據結構——語法樹,然后把語法樹傳給代碼生成器(code generator)進行處理。SQLite分詞器的代碼是手工編寫的,分析器代碼是由SQLite定制的分析器生成器(稱為Lemon)生成的。The Lemon parser generator is designed for high performance and takes special precautions to guard against memory leaks. 一旦SQL語句被分解為串值并組織到語法樹中,分析器就將該樹下傳給代碼生成器進行處理。而代碼生成器根據它生成一種SQLite專用的匯編代碼,最后由虛擬機(Virtual Machine)執行。
## 虛擬機(Virtual?Machine)
架構中最核心的部分是虛擬機,或者叫做虛擬數據庫引擎(Virtual DataBase Engine,VDBE)。它和Java虛擬機相似,解釋執行字節代碼。VDBE的字節代碼(稱為虛擬機語言)由128個操作碼(opcodes)構成,主要是進行數據庫操作。它的每一條指令或者用來完成特定的數據庫操作(比如打開一個表的游標、開始一個事務等),或者為完成這些操作做準備。總之,所有的這些指令都是為了滿足SQL命令的要求。VDBE的指令集能滿足任何復雜SQL命令的要求。所有的SQLite SQL語句——從選擇和修改記錄到創建表、視圖和索引——都是首先編譯成此種虛擬機語言,組成一個獨立程序,定義如何完成給定的命令。例如,在SQLite的CLP中執行下面語句:
```
sqlite> .m col
sqlite> .h on
sqlite> .w 4 15 3 3 3 10 3
sqlite> explain SELECT name FROM episodes LIMIT 10;
SQLite會顯示編譯后的VDBE匯編程序,如列表1-1所示。
列表1-1 VDBE匯編程序
addr? opcode?????????? p1?? p2?? p3?? p4?????????????? p5??? comment
----? ---------------? ---? ---? ---? ---------------? ----? ----------
0???? Trace??????????? 0??? 0??? 0???????????????????? 00
1? ???Integer????????? 10?? 1??? 0???????????????????? 00
2???? MustBeInt??????? 1??? 0??? 0???????????????????? 00
3???? IfZero?????????? 1??? 13?? 0???????????????????? 00
4???? Goto???????????? 0??? 14?? 0???????????????????? 00
5???? OpenRead???????? 0?? ?2??? 0??? 3??????????????? 00
6???? Rewind?????????? 0??? 12?? 0???????????????????? 00
7???? Column?????????? 0??? 2??? 2???????????????????? 00
8???? ResultRow??????? 2??? 1??? 0???????????????????? 00
9???? AddImm?????????? 1??? -1?? 0???????????????? ????00
10??? IfZero?????????? 1??? 12?? 0???????????????????? 00
11??? Next???????????? 0??? 7??? 0???????????????????? 01
12??? Close??????????? 0??? 0??? 0???????????????????? 00
13??? Halt???????????? 0??? 0??? 0???????????????????? 00
14??? Transaction????? 0??? 0??? 0???????????????????? 00
15??? VerifyCookie???? 0??? 40?? 0???????????????????? 00
16??? TableLock??????? 0??? 2??? 0??? episodes???????? 00
17??? Goto???????????? 0??? 5??? 0???????????????????? 00
```
程序由17條指令組成。通過對給定的操作數完成特別的操作,這些指令將會返回episodes表前10個記錄的name字段的值。episodes表是本書示例數據庫的一部分。
從多個方面都可以看出,VDBE是SQLite的核心:它上面的各模塊都是用于創建VDBE程序,它下面的各模塊都是用于執行VDBE程序,每次執行一條指令。
## 后端(Back-end)
后端由B-tree、頁緩沖(page cache,pager)和操作系統接口(即系統調用)構成。B-tree和page cache共同對數據進行管理。它們操作的是數據庫頁,這些頁具有相同的大小,就像集裝箱。頁里面的“貨物”是表示信息的大量bit,這些信息包括記錄、字段和索引入口等。B-tree和pager都不知道信息的具體內容,它們只負責“運輸”這些頁,頁不關心這些“集裝箱”里面是什么。
B-tree的主要功能就是索引,它維護著各個頁之間的復雜的關系,便于快速找到所需數據。它把頁組織成樹型的結構(這是它名稱的由來),這種樹是為查詢而高度優化了的。Page為B-tree服務,為它提供頁。Pager的主要作用就是通過OS接口在B-tree和磁盤之間傳遞頁。磁盤操作是計算機到目前為止所必須做的最慢的事情。所以,pager 盡力提高速度,其方法是把經常使用的頁存放到內存當中的頁緩沖區里,從而盡量減少操作磁盤的次數。它使用特殊的算法來預測下面要使用哪些頁,從而使B-tree能夠更快地工作。
## 工具和測試代碼(Utilities?and?Test?Code)?
工具模塊中包含各種各樣的實用功能,還有一些如內存分配、字符串比較、Unicode轉換之類的公共服務也在工具模塊中。這個模塊就是一個包羅萬象的工具箱,很多其它模塊都需要調用和共享它。
測試模塊中包含了無數的回歸測試語句,用來檢查數據庫代碼的每個細微角落。這個模塊是SQLite性能如此可靠的原因之一。
## SQLite 的特色
盡管SQLite是如此之小,卻提供了如此之多的特色和性能。它支持ANSI SQL92的一個大子集(包括事務、視圖、檢查約束、關聯子查詢和復合查詢等),還支持其它很多關系型數據庫的特色,如觸發器、索引、自動增長字段和LIMIT/OFFSET子句等。SQLite還有很多獨特的特色,如內在數據庫、動態類型和沖突解決(下面解釋)。
如本章開始時所述,在SQLite的觀念和實現中,都遵循著一系列指導原則。下面就來詳述這些原則。
## 零配置
從SQLite的設計之始,就沒準備在應用時使用DBA。配置和管理SQLite就像得到它一樣簡單。SQLite包含了正好適合于一個程序員的腦筋的特色。
## 兼容性
SQLite在設計時特別注意了兼容性。它可以編譯運行在Windows、Linux、BSD、Mac OS X及商用的Unix 系統如Solaris、HPUX和AIX,還可以應用于很多嵌入式平臺如QNX、VxWorks、Symbian、Palm OS和Windows CE。它可以無縫地工作在16-bit、32-bit和64-bit體系結構中并且能同時適應字節的大端格式和小端格式。SQLite的兼容性并不只表現在代碼上,還表現在其數據庫文件上。SQLite的數據庫文件在其所支持的所有操作系統、硬件體系結構和字節順序上都是二進制一致的。你可以在Sun SPARC工作站上創建一個SQLite數據庫然后在Mac或Windows的機器上——甚至移動電話上——使用它,而不需要做任何轉換和修改。此外,SQLite數據庫可以支撐2TB的數據量(受操作系統限制),還內置地同時支持UTF-8和UTF-16編碼。
## 緊湊性
SQLite的設計可以說是功能齊全但體積很小:1個頭文件,1個庫,不需要擴展的數據庫服務。所有的東西,包括客戶端、服務器和虛擬機等,都被打包在1/4兆大小之內。如果在編譯時去掉一些不需要的特性,程序庫可以縮小至170KB (在x86硬件平臺上使用GNU C進行編譯)。此外,還有一個SQLite的私有版本,大小是69KB,可以運行在智能卡上(參“附加信息”一節)。
空注:我下載的DLL有500多KB。
## 簡單
作為程序庫,SQLite的API可以算是最簡單最易用的了。SQLite既有很好的文檔又很容易望文知意。
## 適應性
SQLite的幾個特性使其成為一個適應性極強的數據庫。作為一個內嵌式的數據庫,SQLite在以下兩個方面都做得最好:強有力而可伸縮的關系型數據庫前端,簡單而緊湊的B-tree后端。
## 不受拘束的授權
SQLite的全部代碼都在公共域中,不需要授權。SQLite的任何一部分都沒有附加版權要求。所有曾經為SQLite項目貢獻過代碼的人都簽署過一個宣誓書將他們的貢獻發布到公共域。也就是說,無論你如何使用SQLite的代碼都不會有法律方面的限制。你可以修改、合并、發布、出售或將這些代碼用于任何目的,商業和中非商業的,不需要支付任何費用,不會受到任何限制。
## 可靠性
SQLite的源代碼不但免費,還編寫得很好。SQLite源代碼包含大約30000行標準C代碼,它是干凈的、模塊化的和完好注釋的。SQLite源代碼易理解、易定制。
SQLite的核心軟件(庫和工具)由約30000行代碼組成,但分發的程序中還包含有超過30000行的回歸測試代碼,它們覆蓋了97%的核心代碼。也就是說,超過一半的SQLite項目代碼是專門用于回歸測試的,也就是說,差不多每寫一行功能代碼,都要寫一行測試代碼對它進行測試。
## 易用性
SQLite還提供一些獨特的功能來提高易用性,包括動態類型、沖突解決和“附加”多個數據庫到一個連接的能力。
## 性能和限制
SQLite是一個快速數據庫。但“快速”這個詞本身是一個主觀的和不明確的詞。誠實地講,有些事情SQLite能比其它數據庫做得快,也有些事情不能。這么說吧,利用SQLite提供的配置參數,SQLite是足夠快速和高效的。跟大多數其它數據庫一樣,SQLite使用B-tree處理索引,使用B+tree處理表數據。因此,在對單表進行查詢時,SQLite要快于(或至少相當于)其它數據庫的速度。
在一些情況下SQLite可能不如大型數據庫快,但大多數這些情況是可理解的。SQLite是一個內嵌式的數據庫,設計用于中小規模的應用程序。這些限制是符合設計目的的。很多新用戶錯誤地假設使用SQLite可以代替大型關系型數據庫,這有時行,但有時不行,依賴于你準備用SQLite來做什么。一般情況下,SQLite在三個主要的方面具有局限性:
+ 并發。
+ 數據庫大小。
+ 網絡。
盡管SQLite做得已經很好了,但仍有部分特性未能實現,包括:
+ 外鍵約束
空注:SQLite的最新版本3.6.19好像已經支持了。
+ 完整的觸發器支持。
+ 完整的ALTER TABLE支持。
+ 事務嵌套。
+ RIGHT和FULL OUTER JOIN。
+ 可修改視圖。
+ GRANT和REVOKE。
## 附加信息
SQLite網站有豐富的信息,包括官方文檔、郵件列表、Wiki和其它的一般信息,它的網址是www.sqlite.org。SQLite社區也是很有幫助的,你可能從郵件列表中找到任何你所需要的東西。另外,SQLite的作者提供了SQLite的專業培訓和支持,包括定制程序(如移植到嵌入式平臺)和增強的SQLite版本,這些版本包括內置了加密功能的版本和為嵌入式應用優化的極小化版本。更多的信息可以從www.hwaci.com/sw/sqlite/prosupport.html中找到。