Android SQLite性能分析

作為Android預置的數據庫模塊,對SQLite的深入理解是非常有必要的,可以從中找到一些優化的方向。這裡對SQLite的性能和內存進行瞭一些測試分析,對比瞭不同操作的執行性能和內存占用的情況,粗略地列在這裡算是作個小結。

1. 基本架構

先瞭解一下SQLite主要架構 (詳見《SQLite Definitive Guide》), 需要關註的是Compiler和Backend兩個模塊。正因為有一個虛擬機的存在,所以才有瞭Compiled Statement的價值,因為它可以減少前置的編譯時間,直接到VDBE上執行。而Backend端的Pager,則是重要數據管理者,真正決定者數據操作的性能,以及內存占用。

這裡不再贅述,詳細的內容還是閱讀有關SQLite介結的資料。

2. 性能

這次測試基於Sumsung i9103和Google Nexus S1進行。使用Python腳本及adb指令通過Intent操作Android應用進行數據庫操作。

i. SELECT操作

首先觀察到SELECT在不同記錄數下的峰值分佈,可見整體上有上升的趨勢。正如SQLite官方說的它並不適合存儲大量數據,一定要控制其中的記錄數量。

另外SELECT操作性能也取決於查詢的欄位個數,而@行雲進一步確認和返回欄位的內容大小有關,也就是欄位的內容和多少也需要權衡。

ii. 關於事務

事務是提高SQLite操作性能的一個重要技術,特別是SQLite實現瞭WAL,使得事務與SELECT不會互斥,大大提高瞭應用的性能。參見附2。

下面是未使用事務時,三類操作的平均值:

使用瞭事務後,各個操作的性能大幅下降。

但是問題是事務提交的時間會變長,這個時間一是需要形成新的峰值,另外也要平分到各個操作來看:

vcD48cCBjbGFzcz0=”p1″>所以不能貪多,事務還是要及時提交。另外註意, 雖然Compiled Statement有利於性能表現,但還不如使用事務的效果來得直接。

iii. 不同機型的操作性能

先看SELECT操作的平均值在兩種機型上的表現, 可以看到i9103上的波動性比較大,而Nexsus S1則一直保持穩定:

散點圖,可以觀察到時間分佈情況:

再看另外三個操作的表現(上下兩部分false和true分別表示為未使用事務和使用事務的情況):

運用WAL可以大幅提升性能,不過它也有一個副作用。它會導致數據查詢需要進行兩次,可以理解為一次在db文件,一次在wal文件。具體原因參見<<SQLite Definitive Guide>>最後一章。WAL是滿1000Pages時才會合並到主數據庫裡,這個時機稱為checking point, 可以進行配置。按默認的Page Size:1024計算,也就是當WAL文件接近1M時,進行檢查。如果沒有活動的事務使用這些pages,就會提交。而WAL的大小,對SELECT的影響表現不同。

下面是WAL對查詢性能峰值影響的測試數據(i9103上測試),圖中的true,false表示是否有WAL文件存在。

*整體的平均值相差在1ms,但峰值的才是真正值得註意的。

為瞭避免WAL過大,可以選擇調用SQLiteDatabase::disableWriteAheadLoggingMethod()強制合並到主數據庫文件,這個調用會異步在SQLite內部執行,不會明顯阻塞用戶的線程。

*另外,SQLiteDatabase::query()隻是對SQLiteDatabase::rawQuery()的封裝,多瞭一個字串組裝的過程,反而不如直接使用SQLiteDatabase::rawQuery()。

3. 內存

SQLite以Page為單位存儲數據,默認一個Page有1024字節,然後通過B- Tree組織起來(Table使用B+ Tree組織):

Lookaside則是SQLite應用的內存管理的技術,優化瞭內存的使用效率,主要思想是先分配一整塊內存, 分成若幹個slots,然後SQLite再按需使用。這個許多小內存分配器的思想是一樣的。詳見附1。

再解釋一下Page Cache Overflow, 主要是在一個Page中的記錄的數據無法剛好放在一個Page內,還要使用額外的另一個Page空間, 這就是Overflow Page。

Android還有個萬能dumpsys, 使用dumpsys meminfo可以查看到一個進程的SQLite使用的內存信息。如:

SQL

heap: 265 MEMORY_USED: 265

PAGECACHE_OVERFLOW: 73 MALLOC_SIZE: 46

DATABASES

pgsz dbsz Lookaside(b) cache Dbname

4 60 17 199/114/1 webviewCache.db

1/541/1 (pooled # 1) webviewCache.db

. cache的三個值分別是:

Page Cache的命中次數、未命中次數,以及Page Cache個數。可以在Android源碼中的SQLiteDebug.java以及ActivityThread.java找到細節的內容。

. page size, db size的單位是KBytes, Lookaside(b)是指使用多少個Lookaside的slots。

. 對於Heap和Overflow Pages,SQLiteDatabase的內存回收可能沒有那麼及時,可以調用SQLiteDatabase::releaseMemory()進行主動釋放。

*使用SQLite的PRAGMA可以直接獲取一些通過SQLiteDatabase獲取不到信息,當然如果SQLite不支持,也會拋異常出來,詳見附4。

轉載請註明出處: http://blog.csdn.net/horkychen SQLite是一個非常精致的系統,很值得研究學習。

參考

1. SQLite Dynamic Memory Allocation

2. Write-Ahead Logging 或 SQLite的WAL機制

3. SQLite Definitive Guide (兩處關於架構和Overflow page的截圖來於此書.)

4. PRAGMA Statement

5. 官方文檔

6. NEC關於Android系統上存儲器操作性能的研究報告

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *