我們首先來看 sqlite 損壞的原因,sqlite官網(上列出以下幾點:
但是我們通過收集到的大量案例和日誌,分析出實際上移動端資料庫損壞的真正原因其實就3個:
我們需要針對這些原因一一進行優化。
2.1、優化空間占用
2.2、優化檔案 sync
2.2.1、synchronous = full
設定sqlite的檔案同步機制為全同步,亦即要求每個事物的寫操作是真的flush到檔案裡去。
2.2.1、fullfsync = 1
2.3、優化效果
多管齊下之後,我們成功將損壞率降低了一半多;db損壞還是無法完全避免,我們還是得提高修復成功率。
3.1、master 表
首先我們來看 sqlite 的架構。sqlite 使用 b+樹 儲存乙個表,整個 sqlite 資料庫就是這些 b+樹 組成的森林。對於每個表的元資料(表名、根節點位址、表 scheme 等),都記錄在乙個叫 sql_master 的表中。這個 sql_master 表(下簡稱 master 表) 本身也是乙個 b+樹 儲存的普通表。
3.2、官方修復演算法率低下原因
官方修復演算法是這樣乙個流程:從 master 表中讀出乙個個表的資訊,根據根節點位址和創表語句來 select 出表裡的資料,能 select 多少是多少,然後插入到乙個新 db 中。要注意的是 master 表他本身也是乙個 b+樹 形式的普通表,db 第0頁就是他的根節點。那麼只要 master 表某個節點損壞,這個節點下面記錄的表就都恢復不了。更壞的情況是 db 第0頁損壞,那麼整個 master 表都讀不出來,就導致整個db都恢復失敗。這就是官方修復演算法成功率這麼低的原因,太依賴 master 表了。
3.3、備份 master 表
那麼最自然的想法,自然是另外備份乙份 master 表了,也不需要用b+樹,直接用陣列序列化儲存就好。我們只需要每隔一段時間輪詢 master 表,看看最近有沒有增刪 table,有的話就全量備份。
3.3.1、備份時機
這裡有個擔憂,就是普通資料表的插入會不會導致表的根節點發生變化,也就是說 master 表會不會頻繁變化,如果變化很頻繁的話,我們就不能簡單地進行輪詢方案了。通過分析原始碼,我們發現 sqlite 裡面 b+樹 演算法的實現是 向下** 的,也就是說當乙個葉子頁滿了需要**時,原來的葉子頁會成為內部節點,然後新申請兩個頁作為他的葉子頁。這就保證了根節點一旦定下來,是再也不會變動的。實際的**除錯也證實了我們這個推論。所以說 master 表只會在新建立表或者刪除乙個表時才會發生變化,我們完全可以採用定時輪詢方案。
3.3.2、備份檔案有效性
接下來的難題是既然 db 可以損壞,那麼這個備份檔案也會損壞,怎麼辦呢?我們採用了 雙備份 的機制。具體來說就是會有新舊兩個備份檔案,每個檔案頭都加上 crc 校驗;每次備份時,從兩個備份檔案中選出乙個進行覆蓋。具體怎麼選呢?優先選損壞那個備份檔案,如果兩個都有效,那麼就選相對較舊的。這就保證了即使本次寫入導致檔案損壞,還有另外乙份備份可以用。這個做法跟 realm 標榜的 mvcc(多版本併發控制)的做法有異曲同工之妙,相當於確認新寫入的檔案有效之後,才使用新寫入的檔案,否則還是繼續用舊的有效的檔案。
前面提到 db 損壞的乙個常見場景是空間不足,這種情況下還要分配檔案空間給備份檔案也是會失敗的。為了解決這個問題,我們採取 預先分配空間 的做法,初始值是 32k,大約可存 750 個表的元資訊,後續則按照32k的倍數進行增長。
3.4、優化效果
通過備份 master 表,我們成功將修復成功率提高了一倍多。
SQLite資料庫損壞修復
the database disk image is malformed 進入到sqlite3操作指定的資料庫 或者直接 sqlite3 e item.db 操作此資料庫 sqlite databases main e item.db sqlite tables 顯示列表 檢查資料庫是否損壞 sql...
SQLite資料庫損壞與修復
導致sqlite資料庫損壞的情況大致可歸結為4類 檔案覆蓋問題 檔案鎖問題 資料同步問題 記憶體問題 sqlite資料庫檔案被覆蓋是可能的,畢竟是乙個普通的磁碟檔案,意味著所有的程序都可以開啟和覆蓋,所以不可能完全避免檔案覆蓋的情況。1.多執行緒寫資料庫問題。sqlite資料庫是支援多程序併發讀寫,...
討論SQLite資料庫損壞與修復
昨晚,朋友和我反饋sqlite資料庫發生損壞有沒有辦法恢復。大致的情況是這樣的,當資料庫在使用時不小心用了新的檔案覆蓋資料庫,導致了sqlite資料庫出現了損壞,開啟的時候出現要輸入密碼,而且不能把sql語句dump下來。所以,文章這裡整理sqlite資料庫出現損壞的所有情況,以及如何修復損壞的sq...