下面是對(duì)LevelDB、TreeDB、SQLite3 這幾個(gè)數(shù)據(jù)庫(kù)的性能對(duì)比測(cè)試,分別使用了LevelDB (revision 39) SQLite3 (version 3.7.6.3) 及 Kyoto Cabinet’s (version 1.2.67)這三個(gè)版本的數(shù)據(jù)庫(kù)。
測(cè)試機(jī)器配置:six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz
文件系統(tǒng):測(cè)試腳本分別跑在兩臺(tái)機(jī)器上,其文件系統(tǒng)一臺(tái)為ext3(磁盤(pán)為 SATA Hitachi HDS721050CLA362),一臺(tái)為ext4(配備磁盤(pán) SATA Samsung HD502HJ)
性能測(cè)試源碼:
基本測(cè)試
基本測(cè)試的條件如下:
- 每個(gè)數(shù)據(jù)庫(kù)使用4GB內(nèi)存
- 數(shù)據(jù)庫(kù)都處于異步寫(xiě)模式(LevelDB’s sync option, TreeDB’s OAUTOSYNC option, SQLite3’s synchronous options 都關(guān)閉),也就是說(shuō)寫(xiě)操作不用等數(shù)據(jù)真正寫(xiě)到磁盤(pán)上才返回。
- Key 的長(zhǎng)度為16字節(jié)
- Value 的長(zhǎng)度為100字節(jié) (這個(gè)長(zhǎng)度才能讓數(shù)據(jù)庫(kù)的壓縮算法能夠起作用,將數(shù)據(jù)壓縮至50%大小左右)
- 順序讀寫(xiě)時(shí)Key值遞增變化
- 隨機(jī)讀時(shí)生成隨機(jī)的Key值
測(cè)試結(jié)果:

結(jié)果顯示,在順序讀寫(xiě)和隨機(jī)寫(xiě)上,LevelDB 在性能上都遙遙領(lǐng)先,在隨機(jī)讀上面 Kyoto Cabinet 引擎稍快一些。
在幾種不同策略下進(jìn)行寫(xiě)操作測(cè)試
A. Values 為長(zhǎng)數(shù)據(jù)(數(shù)據(jù)長(zhǎng)度為100,000字節(jié))

LevelDB在Value較長(zhǎng)時(shí)性能比較低,這是由于LevelDB對(duì)每一次寫(xiě)操作都會(huì)至少進(jìn)行兩次寫(xiě)動(dòng)作,一次是寫(xiě)數(shù)據(jù)文件,另一次是寫(xiě)日志文件。這里慢的主要原因是LevelDB在進(jìn)行這些操作時(shí)對(duì)值進(jìn)行了過(guò)多的Copy。
B. 批量寫(xiě)操作
一次寫(xiě)操作寫(xiě)1000條100字節(jié)的數(shù)據(jù),由于TreeDB不支持批量寫(xiě)入,故未對(duì)其進(jìn)行對(duì)比測(cè)試

上面結(jié)果是由于LevelDB數(shù)據(jù)的組織方式,導(dǎo)致順序?qū)懞碗S機(jī)寫(xiě)在性能上都變化不大。
C. 同步進(jìn)行寫(xiě)操作
- 對(duì) LevelDB, 設(shè)置 WriteOptions.sync = true.
- 對(duì) TreeDB, 將 TreeDB’s OAUTOSYNC 選項(xiàng)開(kāi)啟.
- 對(duì) SQLite3, 設(shè)置 “PRAGMA synchronous = FULL”.

如果你看一下ext4文件系統(tǒng)下的測(cè)試數(shù)據(jù),你會(huì)發(fā)現(xiàn)ext3和ext4在表現(xiàn)上非常不同。
D. 無(wú)壓縮的寫(xiě)操作
LevelDB 和 TreeDB 都支持相應(yīng)的數(shù)據(jù)壓縮算法(LevelDB 使用的是 Snappy , TreeDB 使用的是 LZO),由于SQLite不支持壓縮,所以這里的測(cè)試數(shù)據(jù)只是從上面的基本測(cè)試結(jié)果copy過(guò)來(lái)的。

LevelDB開(kāi)啟壓縮比不開(kāi)啟壓縮效率更高,而TreeDB則相反,這可能是由于TreeDB采用的壓縮算法(LZO)與LevelDB采用的壓縮算法(Snappy)相比計(jì)算代價(jià)更高。
E. 使用更大內(nèi)存
將每個(gè)獨(dú)立庫(kù)的內(nèi)存增大到128MB,對(duì)LevelDB來(lái)說(shuō),其中120MB用來(lái)做 write buffer,另外8MB用來(lái)做 cache(原來(lái)是2MB的 write buffer 和2MB的cache),對(duì)SQLite來(lái)說(shuō),我們不改變其page size,還是保持為1kb,但是我們?cè)龃笃鋚age數(shù)量從4k增加到128k,對(duì)TreeDB來(lái)說(shuō),我們同樣不改變其page大小,也只是增大其cache,從4MB增大到128MB。

SQLite 在采用了大內(nèi)存后性能變化并不大,而 LevelDB 和 TreeDB 的隨機(jī)寫(xiě)性能卻有顯著提高。LevelDB 在增大內(nèi)存后性能提升的原因是其write buffer 更大,從而減少了創(chuàng)建的sorted file的次數(shù)。減少了磁盤(pán)IO。而 TreeDB 的性能提升原因是由于其數(shù)據(jù)庫(kù)的更大部分被映射到內(nèi)存中了。
在幾種不同策略下進(jìn)行讀操作測(cè)試
A. 大的Cache空間
我們分配128MB給每個(gè)數(shù)據(jù)庫(kù),對(duì)LevelDB來(lái)說(shuō),我們分配8MB給 write buffer,120MB給cache,對(duì)另外兩個(gè)數(shù)據(jù)庫(kù),由于它們不支持區(qū)分 write buffer 和cache,所以統(tǒng)一將 cache size設(shè)置成128MB。

從結(jié)果可以看到,增大Cache在數(shù)據(jù)庫(kù)讀性能上都有所提升,其中最為顯著的是TreeDB,其隨機(jī)讀性能大幅提升。主要是由于有足夠的內(nèi)存使得其所有讀操作都幾乎是在內(nèi)存中進(jìn)行。
B. 無(wú)壓縮的讀操作
下面結(jié)果是我們對(duì)預(yù)先無(wú)壓縮狀態(tài)寫(xiě)入的100萬(wàn)條key為16字節(jié)、value為100字節(jié)的數(shù)據(jù)后進(jìn)行的讀性能測(cè)試。同樣的 SQLite 由于不支持壓縮,所以下面數(shù)據(jù)是直接從其基本測(cè)試上copy過(guò)來(lái)的。

結(jié)果可以看到,取消壓縮對(duì)讀取性能提升不是特別大,當(dāng)然,如果你的數(shù)據(jù)都在內(nèi)存中的話,執(zhí)行解壓操作也不會(huì)對(duì)性能造成太大影響。