Sqlite學習筆記(四)&&SQLite-WAL原理

  Sqlite學習筆記(三)&&WAL性能測試中列出了幾種典型場景下WAL的性能數據,瞭解到WAL確實有性能優點,這篇文章將會詳細分析WAL的原理,作到知其然,更要知其因此然。html

WAL是什麼sql

      WAL(Write ahead logging)是一種日誌模式,它是一種思想,廣泛應用於關係型數據庫。每一個事務執行變動時,修改數據頁,同時會產生日誌,這樣在事務提交後,不須要將修改的髒頁刷盤,只須要將事務產生的日誌落盤便可返回。WAL保證日誌必定先於對應的髒頁落盤,就是所謂的WAL。SQLITE在3.7版本之後引入WAL,它的WAL也基本採用這個原理,只不過SQLite實現比較簡單,日誌記錄的是修改後的頁,而不是所謂的修改日誌。WAL模式下,SQlite中除了db文件,還包含了兩個文件,.wal文件和.shm文件,前者是日誌文件,後者是日誌索引文件。數據庫

日誌模式緩存

      SQLite中日誌模式主要有DELETE和WAL兩種,其餘幾種好比TRUNCATE,PERSIST,MEMORY基本原理都與DELETE模式相同,不做詳細展開。DELETE模式採用影子分頁技術(Shadow paging),DELETE模式下,日誌中記錄的變動前數據頁內容;WAL模式下,日誌中記錄的是變動後的數據頁內容。事務提交時,DELETE模式將日誌刷盤,將DB文件刷盤,成功後,再將日誌文件清理;WAL模式則是將日誌文件刷盤,便可完成提交過程。那麼WAL模式下,數據文件什麼時候更新呢?這裏引入了檢查點概念,檢查點的做用就是按期將日誌中的新頁覆蓋DB文件中的老頁,並經過參數wal_autocheckpoint來控制檢查點時機,達到權衡讀寫的目的。併發

     DELETE模式下,寫事務直接更新db-page,並將old-page寫入日誌,讀事務則直接讀db-page,由於db-page中保存了提交的全部事務的更新。事務提交後,直接將日誌文件刪除;若事務須要回滾,則將日誌中old-page中的內容覆蓋db-page,恢復原始內容。WAL模式下,寫事務將更新寫到日志文件中,不更新db-page,事務提交時,也不影響db-page,只是將日誌持久化而已。若事務回滾,則不將日誌寫入文件便可。因爲最新的數據在日誌文件中,那麼如何讀取到最新的數據呢?WAL模式經過end-mark(事務提交位點)達到這一目的。具體而已,事務開始時,會首先掃描日誌文件,獲取最近一個end-mark,在讀取數據時,首先會判斷page是不然在wal日誌文件中存在,由於同一個page,必定是wal文件中的比db文件中的要新。如果存在,則使用,不然,再從db文件中獲取指定的page。從流程上來看,這個過程比較慢,由於極端狀況下,每次讀都須要掃描wal文件和db文件。爲了提升性能,WAL模式中有一個wal-index文件,這個文件記錄了頁號和該頁在WAL文件中的偏移,而且wal-index文件採用共享緩存實現,從文件名也能夠看到,後綴是.shm,所以判斷page是否在wal文件存在的操做實質是一次內存讀。wal-index採用hash表存儲,所以查詢效率也很是高。app

      與傳統的DBMS不一樣,SQLite中記錄的日誌,實質是dirty-page,重作實質是對利用WAL中的日誌頁覆蓋db-page,這種實現方式比較簡單,同時也比較浪費空間,由於一個page是1k,即便只更新1byte,也會致使日誌記錄1k。性能

WAL的優點與劣勢學習

1)  併發優點   測試

      SQLite爲何引入WAL,必定是WAL有不少好的特性。其中最主要的一點是WAL支持讀寫併發。在DELETE模式下,讀寫是互斥的。爲何WAL能夠併發,而DELETE不行?我這裏不打算詳細展開WAL模式和DELETE模式的鎖機制,後面有機會再單獨寫這一部分。從上面一節的分析能夠知道,WAL模式下,寫事務以append方式記錄new-page,而讀事務只會讀取db-page和end-mark以前的wal日誌,所以不會發生讀寫衝突的問題,讀寫能夠併發。而DELETE模式下,寫事務寫的是db-page,讀事務也是讀db-page,因此讀寫不能併發。spa

2) 寫性能優點

 從前面的分析可知,WAL模式下,事務提交只須要寫入日誌文件便可,爲了持久化,只須要一次fsync調用。而DELETE模式下,事務提交過程當中,首先要確保日誌落盤(保存old-page,用來rollback),這裏須要一次fsync調用,而後再執行db文件刷盤,這裏還須要一次fsync,而且修改的db-page多是離散的,也會影響性能。而WAL寫日誌都是順序寫,相對於離散寫又有很大的優點。所以DELETE模式下寫性能會比WAL模式要差。測試結果也證實了這一點,這裏能夠參考測試報告。

3) WAL劣勢

      開啓WAL後,每次讀取page,都須要經過wal-index來確認page是否在WAL中,這個會產生必定的性能損耗。另外,會引入WAL文件,這個文件若是使用不當,可能會急劇膨脹,WAL文件變大後,意味着檢索wal-index的代價也變高。並且因爲SQLite通常用於端設備,空間也比較稀缺,所以要嚴格控制好WAL文件的大小。此外,WAL的索引文件採用共享內存實現,所以訪問SQlite的進程不能跨機器。

開啓WAL模式

      經過命令pragma journal_mode=wal能夠開啓wal模式。前面咱們提到開啓WAL模式後,若是使用不當,可能致使WAL文件空間暴增,但咱們有辦法避免這種狀況發生。這裏主要介紹兩個參數,wal_autocheckpoint和journal_size_limit。wal_autocheckpoint用來設置觸發檢查點的時機,默認是1000頁,即當日志增加到1000頁時,開始作檢查點操做。這裏要說明一點的是,SQLite中沒有單獨的檢查點線程,若是設置1000,則觸發寫1000頁的事務來進行檢查點操做。所以這個事務的響應時間會比較長,而其它事務則不受影響。用來設置日誌文件的大小,默認狀況爲-1,當這個參數設置時,若累計更新頁大小超過journal_size_limit,也會致使檢查點觸發,用以重複利用日誌文件,避免日誌繼續增加。

問題
1. WAL模式下,檢查點是否會致使鎖等待?
     檢查點包括自動檢查點和手動檢查點。經過PRAGMA wal_autocheckpoint=N命令,能夠設置自動檢查點,當N<=0時,自動檢查點關閉,全部自動檢查點的類型都是PASSIVE。默認狀況下,自動檢查點是開啓的,N爲1000。對於PASSIVE類型的檢查點,不會影響讀寫事務。經過 PRAGMA schema.wal_checkpoint 命令能夠手工觸發一次檢查點,好比PRAGMA schema.wal_checkpoint(PASSIVE)觸發一次PASSIVE類型檢查點,PRAGMA schema.wal_checkpoint(FULL)觸發一次FULL類型檢查點。對於FULL類型,因爲須要將全部更新合併到DB文件,若是有讀寫事務沒有結束,則須要等待;並且作檢查點過程當中,會堵塞新的讀寫事務。因此PASSIVE類型不會致使鎖等待,而FULL類型,RESTART和TRUNCATE類型,會致使鎖等待。
2. 檢查點是否會致使事務響應時間變長?
     對於自動檢查點,根據wal_autocheckpoint=N設置,當更新page超過N時會觸發一次檢查點,那麼當前的這個事務就須要等檢查點執行完畢才返回,因此觸發檢查點的事務響應時間會變長。

3.WAL隔離級別是什麼?
     WAL模式下,讀寫能夠併發,事務可否得到新數據的關鍵點在於wal-index的位點,SQLite中,只會在每一個事務開始時獲取一次位點,事務中屢次讀位點都是同一個,所以隔離級別是可重複讀。

相關參數

1)  journal_mode(日誌模式)

默認是DELETE模式

DELETE:原始數據頁存放在日誌文件中,事務提交時,將文件刪除。

TRUNCATE :與DELETE模式的區別是,清空日誌文件,但不刪除文件清空文件每每比刪除文件要快。

PERSIST:與DELETE和TRUNCATE模式區別是,既不刪除文件,也不清空文件,而是將日誌文件第一個頁設置標記(置0),這個也是爲了提升性能。
MEMORY :內存模式,修改不落盤,沒法保證事務的原子性。

OFF:不開啓日誌,這樣無法保證事務的原子性。

WAL :write ahead log,3.7.0引入,日誌中記錄修改頁,提交時只需刷修改頁。

2)  journal_size_limit(日誌文件大小)

默認值爲-1,表示沒有限制,單位是字節。
DELETE模式下,當日志增加超過閥值時,則進行截斷。
WAL模式下,當日志增加超過閥值時,日誌文件再也不會被截斷,而是重複利用,
由於一般狀況下重複寫的性能要好於追加的性能,並且也省磁盤空間。
default_journal_size_limit,用於設置日誌文件的默認大小。

3)  wal_checkpoint(檢查點模式)

PASSIVE,默認自動檢查點和主動檢查點都是PASSIVE類型,將全部可以同步到db的數據都進行同步(不超過全部線程的end mark),不持有排它鎖,所以不會影響其餘讀寫事務。

FULL,將wal與db文件徹底同步,須要等待全部讀寫事務都結束,而且會堵塞新的讀寫事務

RESTART,與FULL模式的區別是,下一個寫線程從頭開始寫wal文件。
TRUNCATE,與FULL模式的區別是,將wal文件截斷爲0。

4) wal_autocheckpoint(檢查點觸發時機)

默認值爲1000頁,單位是頁。當日志的增量到N頁時,觸發檢查點操做,將wal_autocheckpoint設置爲0或者-1,表示關閉檢查點。

5) synchronous(同步模式)

默認設置是FULL

0(OFF):事務提交時,不做sync操做,直接返回。

1(NORMAL):事務提交時,日誌頭不做sync操做

2(FULL):每次事務提交,都強制刷日誌(WAL),強制數據頁(journal)

6) cache_size
默認值2000,單位爲頁
修改db的緩存頁數目,臨時生效

7) default_cache_size

默認值2000,單位爲頁

修改緩存頁數目,永久生效若同時設置了cache_size和default_cache_size,以default_cache_size爲準

參考文檔

https://www.sqlite.org/wal.html

相關文章
相關標籤/搜索