2005 年 4 月 01 日 Berkeley DB是歷史悠久的嵌入式數據庫系統,主要應用在UNIX/LINUX操作系統上,其設計思想是簡(jiǎn)單、小巧、可靠、高性能。本文是對DB開(kāi)發(fā)的一個(gè)入門(mén)級指南,重點(diǎn)討論了DB的核心數據結構和數據訪(fǎng)問(wèn)算法,并通過(guò)實(shí)際的代碼演示如何使用DB。最后有一個(gè)對DB的簡(jiǎn)單總結,并提出作者對工具選擇的一些感想。 UNIX/LINUX平臺下的數據庫種類(lèi)非常多,參考資料1中列舉了其中的大部分。通常,我們在設計UNIX/LINUX平臺下的應用軟件時(shí),如果數據種類(lèi)繁多,數據與數據之間關(guān)系比較復雜,就會(huì )選用一些大型的企業(yè)級數據庫系統,如DB2,ORACLE、SYBASE等,如果軟件規模不大,就傾向選用如MYSQL、POSTGRESQL等中小型數據庫。例如使用PHP/PERL + MYSQL/POSTGRESQL設計網(wǎng)站基本上是一個(gè)很常規的做法。但是,當應用軟件管理的數據類(lèi)型較少(特別注意:這并不是說(shuō)需要管理的數據量?。?,數據管理本身不復雜,且對數據操作要求高效率,則由大名鼎鼎的Berkeley(美國加州大學(xué)伯克利分校)開(kāi)發(fā)的 Berkeley DB可能是一個(gè)很明智的選擇。
DB最初開(kāi)發(fā)的目的是以新的HASH訪(fǎng)問(wèn)算法來(lái)代替舊的hsearch函數和大量的dbm實(shí)現(如AT&T的dbm,Berkeley的ndbm,GNU項目的gdbm),DB的第一個(gè)發(fā)行版在1991年出現,當時(shí)還包含了B+樹(shù)數據訪(fǎng)問(wèn)算法。在1992年,BSD UNIX第4.4發(fā)行版中包含了DB1.85版?;旧险J為這是DB的第一個(gè)正式版。在1996年中期,Sleepycat軟件公司成立,提供對DB的商業(yè)支持。在這以后,DB得到了廣泛的應用,當前最新版本是4.3.27。 DB支持幾乎所有的現代操作系統,如LINUX、UNIX、WINDOWS等,也提供了豐富的應用程序接口,支持C、C++、JAVA、PERL、TCL、PYTHON、PHP等。DB的應用十分廣泛,在很多知名的軟件中都能看到其身影。例如參考資料2中作者談到利用DB在LINUX下實(shí)現內核級文件系統;參考資料3中通過(guò)實(shí)際測試數據說(shuō)明DB提高了OPENLDAP的效率。LINUX下的軟件包管理器RPM也使用DB管理軟件包相關(guān)數據,可以使用命令file查看RPM數據目錄/var/lib/rpm下的文件,則有形式如下的輸出: Dirnames: Berkeley DB (Btree, version 9, native byte-order) 值得注意的是DB是嵌入式數據庫系統,而不是常見(jiàn)的關(guān)系/對象型數據庫,對SQL語(yǔ)言不支持,也不提供數據庫常見(jiàn)的高級功能,如存儲過(guò)程,觸發(fā)器等。
DB的設計思想是簡(jiǎn)單、小巧、可靠、高性能。如果說(shuō)一些主流數據庫系統是大而全的話(huà),那么DB就可稱(chēng)為小而精。DB提供了一系列應用程序接口(API),調用本身很簡(jiǎn)單,應用程序和DB所提供的庫在一起編譯成為可執行程序。這種方式從兩方面極大提高了DB的效率。第一:DB庫和應用程序運行在同一個(gè)地址空間,沒(méi)有客戶(hù)端程序和數據庫服務(wù)器之間昂貴的網(wǎng)絡(luò )通訊開(kāi)銷(xiāo),也沒(méi)有本地主機進(jìn)程之間的通訊;第二:不需要對SQL代碼解碼,對數據的訪(fǎng)問(wèn)直截了當。 DB對需要管理的數據看法很簡(jiǎn)單,DB數據庫包含若干條記錄,每一個(gè)記錄由關(guān)鍵字和數據(KEY/VALUE)構成。數據可以是簡(jiǎn)單的數據類(lèi)型,也可以是復雜的數據類(lèi)型,例如C語(yǔ)言中結構。DB對數據類(lèi)型不做任何解釋, 完全由程序員自行處理,典型的C語(yǔ)言指針的"自由"風(fēng)格。如果把記錄看成一個(gè)有n個(gè)字段的表,那么第1個(gè)字段為表的主鍵,第2--n個(gè)字段對應了其它數據。DB應用程序通常使用多個(gè)DB數據庫,從某種意義上看,也就是關(guān)系數據庫中的多個(gè)表。DB庫非常緊湊,不超過(guò)500K,但可以管理大至256T的數據量。 DB的設計充分體現了UNIX的基于工具的哲學(xué),即若干簡(jiǎn)單工具的組合可以實(shí)現強大的功能。DB的每一個(gè)基礎功能模塊都被設計為獨立的,也即意味著(zhù)其使用領(lǐng)域并不局限于DB本身。例如加鎖子系統可以用于非DB應用程序的通用操作,內存共享緩沖池子系統可以用于在內存中基于頁(yè)面的文件緩沖。
數據庫句柄結構DB:包含了若干描述數據庫屬性的參數,如數據庫訪(fǎng)問(wèn)方法類(lèi)型、邏輯頁(yè)面大小、數據庫名稱(chēng)等;同時(shí),DB結構中包含了大量的數據庫處理函數指針,大多數形式為 (*dosomething)(DB *, arg1, arg2, …)。其中最重要的有open,close,put,get等函數。 數據庫記錄結構DBT:DB中的記錄由關(guān)鍵字和數據構成,關(guān)鍵字和數據都用結構DBT表示。實(shí)際上完全可以把關(guān)鍵字看成特殊的數據。結構中最重要的兩個(gè)字段是 void * data和u_int32_t size,分別對應數據本身和數據的長(cháng)度。 數據庫游標結構DBC:游標(cursor)是數據庫應用中常見(jiàn)概念,其本質(zhì)上就是一個(gè)關(guān)于特定記錄的遍歷器。注意到DB支持多重記錄(duplicate records),即多條記錄有相同關(guān)鍵字,在對多重記錄的處理中,使用游標是最容易的方式。 數據庫環(huán)境句柄結構DB_ENV:環(huán)境在DB中屬于高級特性,本質(zhì)上看,環(huán)境是多個(gè)數據庫的包裝器。當一個(gè)或多個(gè)數據庫在環(huán)境中打開(kāi)后,環(huán)境可以為這些數據庫提供多種子系統服務(wù),例如多線(xiàn)/進(jìn)程處理支持、事務(wù)處理支持、高性能支持、日志恢復支持等。 DB中核心數據結構在使用前都要初始化,隨后可以調用結構中的函數(指針)完成各種操作,最后必須關(guān)閉數據結構。從設計思想的層面上看,這種設計方法是利用面向過(guò)程語(yǔ)言實(shí)現面對對象編程的一個(gè)典范。
在數據庫領(lǐng)域中,數據訪(fǎng)問(wèn)算法對應了數據在硬盤(pán)上的存儲格式和操作方法。在編寫(xiě)應用程序時(shí),選擇合適的算法可能會(huì )在運算速度上提高1個(gè)甚至多個(gè)數量級。大多數數據庫都選用B+樹(shù)算法,DB也不例外,同時(shí)還支持HASH算法、Recno算法和Queue算法。接下來(lái),我們將討論這些算法的特點(diǎn)以及如何根據需要存儲數據的特點(diǎn)進(jìn)行選擇。 B+樹(shù)算法:B+樹(shù)是一個(gè)平衡樹(shù),關(guān)鍵字有序存儲,并且其結構能隨數據的插入和刪除進(jìn)行動(dòng)態(tài)調整。為了代碼的簡(jiǎn)單,DB沒(méi)有實(shí)現對關(guān)鍵字的前綴碼壓縮。B+樹(shù)支持對數據查詢(xún)、插入、刪除的常數級速度。關(guān)鍵字可以為任意的數據結構。 HASH算法:DB中實(shí)際使用的是擴展線(xiàn)性HASH算法(extended linear hashing),可以根據HASH表的增長(cháng)進(jìn)行適當的調整。關(guān)鍵字可以為任意的數據結構。 Recno算法: 要求每一個(gè)記錄都有一個(gè)邏輯紀錄號,邏輯紀錄號由算法本身生成。實(shí)際上,這和關(guān)系型數據庫中邏輯主鍵通常定義為int AUTO型是同一個(gè)概念。Recho建立在B+樹(shù)算法之上,提供了一個(gè)存儲有序數據的接口。記錄的長(cháng)度可以為定長(cháng)或不定長(cháng)。 Queue算法:和Recno方式接近, 只不過(guò)記錄的長(cháng)度為定長(cháng)。數據以定長(cháng)記錄方式存儲在隊列中,插入操作把記錄插入到隊列的尾部,相比之下插入速度是最快的。 對算法的選擇首先要看關(guān)鍵字的類(lèi)型,如果為復雜類(lèi)型,則只能選擇B+樹(shù)或HASH算法,如果關(guān)鍵字為邏輯記錄號,則應該選擇Recno或Queue算法。當工作集關(guān)鍵字有序時(shí),B+樹(shù)算法比較合適;如果工作集比較大且基本上關(guān)鍵字為隨機分布時(shí),選擇HASH算法。Queue算法只能存儲定長(cháng)的記錄,在高的并發(fā)處理情況下,Queue算法效率較高;如果是其它情況,則選擇Recno算法,Recno算法把數據存儲為平面文件格式。
游標是依賴(lài)于數據庫句柄的,應用程序代碼框架如下:
在游標打開(kāi)后,可以以多種方式遍歷特定記錄。
當想查詢(xún)特定關(guān)鍵字對應的記錄,則應對關(guān)鍵字賦值,并把cur->c_get()函數中標志位設置為DB_SET。例如:
游標的作用還有很多,如查詢(xún)多重記錄,插入/修改/刪除記錄等。
本文前面已說(shuō)明環(huán)境是DB數據庫的包裝器,提供多種高級功能。應用程序代碼框架如下:
從DB的官方站點(diǎn)http://www.sleepycat.com/下載最新的軟件包db-4.3.27.tar.gz,解壓到工作目錄,進(jìn)入該目錄,依次執行下列三條命令即可。
執行make uninstall,則可卸載已安裝的DB軟件。 DB缺省把庫和頭文件安裝在目錄/usr/local/BerkeleyDB.4.3/下,使用gcc test.c -ggdb -I/usr/local/BerkeleyDB.4.3/include/ -L/usr/local/BerkeleyDB.4.3/lib/ -ldb -lpthread就可正確編譯程序。如果讀者的測試主機操作系統為RED HAT9,則安裝的DB版本可能是4.0。特別要注意到這兩個(gè)版本的庫是不兼容的。例如打開(kāi)數據庫函數DB->open(),在4.0版本中入參為6個(gè),而在4.3版中則為7個(gè)(可自行比較兩個(gè)庫的頭文件db.h中DB->open函數的定義)。因為在DB相關(guān)的應用程序中,open函數基本上都是要執行的,所以如果函數和版本不匹配,編譯肯定會(huì )出錯。當然,編譯完成后,可以使用命令ldd查看庫的依賴(lài)關(guān)系。
DB是一個(gè)具有工業(yè)強度的嵌入式數據庫系統,數據處理的效率很高。DB功能的穩定性歷經(jīng)時(shí)間的考驗,在大量應用程序中使用便是明證??梢韵胍?jiàn),在同等代碼質(zhì)量的條件下,軟件的BUG數和代碼的長(cháng)度是成正比的,相對幾十兆、幾百兆大型數據庫軟件,DB的只有不到500K的大??! 從實(shí)現功能上看,DB是輕量級數據庫系統,或可稱(chēng)為"極" 輕量級數據庫系統。但是,我認為不能因此而心存輕視之意,所謂"尺有所短,寸有所長(cháng)",以絕對角度比較工具之間的好壞是沒(méi)有什么意義的,關(guān)鍵在于對工具的選擇和運用(似乎可以參考一下極限編程的思想)。也許,正確的"表達范式"應該是:在當前應用背景下,選擇這種工具是最合適的。 |
聯(lián)系客服