最全面的wcdb入門和總結(jié)
開(kāi)篇前的思考:一個(gè)優(yōu)秀的數(shù)據(jù)庫(kù)需要具備什么樣的特性冯遂?
第一:高效档冬。高效的增刪查改是數(shù)據(jù)庫(kù)最基本的要求
第二:易用瞧柔。一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)操作语稠,我們不需要做什么額外的初始化宋彼、操作等,組件能統(tǒng)一完成這些任務(wù)
第三:完整仙畦。優(yōu)秀的數(shù)據(jù)庫(kù)能完整的覆蓋各種極端場(chǎng)景输涕,包括數(shù)據(jù)庫(kù)損壞、監(jiān)控統(tǒng)計(jì)议泵、復(fù)雜的查詢占贫,優(yōu)秀的日志系統(tǒng)等
WCDB接入與遷移
第一步:引入依賴
第二步:選擇接入的架構(gòu)
第三步:原有sqlcipher的遷移
android.database.* -> com.tencent.wcdb.*
android.database.sqlite.* -> com.tencent.wcdb.database.*
第四步:原有SQLCipher遷移(從加密數(shù)據(jù)庫(kù)往wcdb遷移)
WCDB For Android
1 確定的sqlite版本
在 Android SDK 中桃熄,SQLite 是會(huì)不斷升級(jí)的先口,實(shí)際上使用哪個(gè)版本的 SQLite 取決于 APP 運(yùn)行在哪個(gè)版本的系統(tǒng)上型奥,這是對(duì)開(kāi)發(fā)者來(lái)說(shuō)相當(dāng)不友好,因?yàn)橥瑯拥?SQL 語(yǔ)句會(huì)有不同的性能表現(xiàn)碉京。如果業(yè)務(wù)需要使用 SQLite 的新特性就更加需要確定版本的 SQLite 來(lái)保證新特性在所有手機(jī)上都可用厢汹。
WCDB 由于內(nèi)建了自己的 SQLite 實(shí)現(xiàn)(準(zhǔn)確來(lái)說(shuō)是 SQLCipher),所以 SQLite 版本是確定的谐宙,這規(guī)避了很多開(kāi)發(fā)上的問(wèn)題烫葬。
2 Cursor 實(shí)現(xiàn)優(yōu)化
在實(shí)際使用的很多的場(chǎng)景中,我們都需要去數(shù)據(jù)庫(kù)執(zhí)行查詢數(shù)據(jù)凡蜻,得到cursor搭综,然后通過(guò)cursor,封裝數(shù)據(jù)到我們的list中划栓。這個(gè)查詢過(guò)程中兑巾,數(shù)據(jù)會(huì)緩存到到cursorWindow中,也即是(SQLite → CursorWindow → Java)
Wcdb的優(yōu)化是忠荞,直接切斷cursorWindow蒋歌,通過(guò)SQLiteDirectCursor,將SQLite直接返回到j(luò)ava中委煤。在大部分不需要將 Cursor 傳遞出去的場(chǎng)景堂油,能很好的解決 Cursor 的額外消耗,特別是結(jié)果集大于 2MB 的場(chǎng)合
3 mmicu與動(dòng)態(tài)icu加載
什么是mmicu碧绞?wcdb自帶的分詞器府框,與官方的icu不同的是,wcdb對(duì)中文分詞以及icu庫(kù)加載做了特殊處理头遭。官方的icu庫(kù)會(huì)因?yàn)椴煌腶ndroid系統(tǒng)寓免,附帶不同的中文詞庫(kù),會(huì)帶來(lái)不同的分詞效果计维。 wcdb這樣做袜香,也即是相當(dāng)于統(tǒng)一了各個(gè)版本的分詞效果
動(dòng)態(tài)icu加載:官方ICU 還有一個(gè)嚴(yán)重的問(wèn)題是動(dòng)態(tài)庫(kù)和自帶的數(shù)據(jù)文件體積很大,超過(guò) 10MB鲫惶,WCDB 做了一個(gè)兼容層 icucompat蜈首,通過(guò)系統(tǒng)帶的數(shù)據(jù)文件推斷 ICU 版本, 通過(guò) dlopen 動(dòng)態(tài)加載不同的符號(hào)名稱欠母,然后通過(guò)宏來(lái)模擬直接調(diào)用方便開(kāi)發(fā)欢策。最終實(shí)現(xiàn)效果便是在不需要自帶 ICU 庫(kù)的前提下使用 ICU 庫(kù)的斷詞、歸一化等功能赏淌,為最終 APK 包省下 10MB 以上空間踩寇。
WCDB的性能
從上面可以看出wcdb對(duì)標(biāo)與sqlcipher,在數(shù)據(jù)庫(kù)的插入六水、查詢俺孙、更新方面的性能是有很大的提升的
方案1:官方Dump方案
流程分析
dump方案的原理很簡(jiǎn)單辣卒,主要
思路是讀取db中的sqlite_master表,里面保存著所有的索引睛榄、表名荣茫、建表語(yǔ)句等。
步驟1:讀取create語(yǔ)句场靴,建立新表
步驟2:執(zhí)行select * From語(yǔ)句啡莉,每讀出一行,就輸出一個(gè)insert語(yǔ)句
經(jīng)過(guò)步驟2旨剥,整個(gè)db就已經(jīng)dump出來(lái)了
備注:忽略掉損壞錯(cuò)誤咧欣,繼續(xù)遍歷下個(gè)表,最終可以把所有沒(méi)損壞的表以及損壞了的表的前半部分讀取出來(lái)
思考:官方的方案存在什么問(wèn)題轨帜?
1 耗費(fèi)空間该押。先要保存dump 出來(lái)的SQL的空間,這個(gè) 大概一倍DB大小阵谚,還要另外一倍 DB大小來(lái)新建DB恢復(fù)蚕礼。
2 成功率低,sqlite_master讀取失敗梢什,特別是第一頁(yè)損壞奠蹬,會(huì)導(dǎo)致后續(xù)所有內(nèi)容無(wú)法讀出
3 花費(fèi)時(shí)間長(zhǎng)(后面有對(duì)比圖)
方案2 BackupKit 備份方案(優(yōu)化版Dump + 壓縮)
微信在原先的官方dump+gzip方案上做出了兩點(diǎn)改動(dòng):
1使用了自定義 的二進(jìn)制格式承載Dump輸出∥宋纾恢復(fù)的時(shí)候不需要重復(fù)的編譯SQL語(yǔ)句囤躁,編譯一次就可以 插入整個(gè)表的數(shù)據(jù)了,恢復(fù)性能也有一定提升
2壓縮操作則放到別的線程同時(shí)進(jìn)行荔睹,在雙核以上的環(huán)境 基本可以做到無(wú)額外時(shí)間消耗狸演。
優(yōu)化前的對(duì)比:
優(yōu)化后備份方案和原來(lái)的dump方案的對(duì)比
方案3:Repair Kit
核心思想:備份sqlite_master表
1 如何判斷備份時(shí)機(jī)?輪詢
2備份文件也會(huì)損壞僻他,怎么辦宵距?
雙備份 的機(jī)制。具體來(lái)說(shuō)就是會(huì)有新舊兩個(gè)備份文件吨拗,每個(gè)文件頭都加上 CRC 校驗(yàn)满哪;每次備份時(shí),從兩個(gè)備份文件中選出一個(gè)進(jìn)行覆蓋劝篷。具體怎么選呢哨鸭??jī)?yōu)先選損壞那個(gè)備份文件,如果兩個(gè)都有效娇妓,那么就選相對(duì)較舊的像鸡。這就保證了即使本次寫(xiě)入導(dǎo)致文件損壞,還有另外一份備份可以用
WCDB 的 WAL和異步checkPoint
原子性提交和回滾操作 的默認(rèn)方法是 rollback journal哈恰,其工作模式如下圖所示
如以上流程圖所示只估,當(dāng)我們需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作的時(shí)候华望,sqlite會(huì)把需要修改的部分copy到j(luò)ournal,以防出現(xiàn)意外的時(shí)候仅乓,可以進(jìn)行回滾。當(dāng)寫(xiě)入完成蓬戚,用戶提交事務(wù)后夸楣,sqlite將會(huì)清空journal,完成一個(gè)完整的寫(xiě)事務(wù)
問(wèn)題是什么子漩?
Rollback 模式中豫喧,每次拷貝原始內(nèi)容或?qū)懭胄聝?nèi)容后,都需要確保之前寫(xiě)入的數(shù)據(jù)真正寫(xiě)入到磁盤(pán)幢泼,而不是緩存在操作系統(tǒng)中紧显,這需要發(fā)起一次 fsync 操作,通知并等待操作系統(tǒng)將緩存真正寫(xiě)入磁盤(pán)缕棵,這個(gè)過(guò)程十分耗時(shí)孵班。除了耗時(shí)的 fsync 操作,寫(xiě)入 -journal 以及 DB 主文件的時(shí)候招驴,是需要獨(dú)占整個(gè) DB 的篙程,否則別的線程/進(jìn)程可能讀取到寫(xiě)到一半的內(nèi)容。這樣的設(shè)計(jì)使得寫(xiě)操作與讀操作是互斥的别厘,并發(fā)性很差
WCDB WAl模式的優(yōu)越性體現(xiàn)在哪虱饿?
從上圖可以看出,wal模式下触趴,寫(xiě)數(shù)據(jù)并不是直接寫(xiě)到-wal文件末尾氮发。讀操作的時(shí)候,將結(jié)合 DB 主文件以及 -wal 的內(nèi)容返回結(jié)果冗懦。由于讀操作只讀取 DB 主文件和 -wal 前面沒(méi)在寫(xiě)的部分爽冕,不需要讀取寫(xiě)操作正在寫(xiě)到一半的內(nèi)容,WAL 模式下讀與寫(xiě)操作的并發(fā)由此實(shí)現(xiàn)寫(xiě)操作需要執(zhí)行Checkpoint才可以把當(dāng)前wal文件中的內(nèi)容合并到db主文件中披蕉。由于寫(xiě)操作將內(nèi)容臨時(shí)寫(xiě)到 -wal 文件扇售,-wal 文件會(huì)不斷增大且拖慢讀操作,因此需要定期進(jìn)行Checkpoint 操作將 -wal 文件保持在合理的大小嚣艇。
性能如何承冰?看看效果
寫(xiě)性能對(duì)比:
讀性能對(duì)比
以上就是wcdb wal模式的對(duì)比,讀性能則如官方文檔所說(shuō)食零,WAL 模式單線程性能要稍稍差于 Rollback 模式困乒,但由于 WAL 模式支持讀寫(xiě)并發(fā),WCDB 也開(kāi)啟了線程池贰谣,因此 WAL 模式的并發(fā)性要遠(yuǎn)遠(yuǎn)好于 Rollback 模式娜搂。
參考:
https://cloud.tencent.com/developer/article/1031030
https://cloud.tencent.com/developer/article/1005623
https://cloud.tencent.com/developer/article/1005534
https://cloud.tencent.com/developer/article/1005513