1. 程式人生 > >SQLite這麼嬌小可愛,不多瞭解點都不行啊

SQLite這麼嬌小可愛,不多瞭解點都不行啊

在我眼裡,MySQL和Oracle是這樣的

而SQLite在是這樣的

所以這麼萌的資料庫,我真的應該多瞭解她的。

簡介

SQLite,是一款輕型的資料庫,是遵守ACID的關係型資料庫管理系統。它的設計目標是嵌入式的,目前Android和iOS的裝置內建的都是SQLite資料庫。SQLite雖然嬌小,但也支援事務和多數的SQL92標準。

主要特點

  • Zero-Configuration 無需安裝和管理配置。
  • Serverless 無需伺服器支援。
  • Single Database File 資料檔案儲存在一個單一的磁碟檔案。
  • Stable Cross-Platform Database File 資料庫檔案格式跨平臺,無論是大小端,或者是32bit或64bit機器都沒有關係
  • Compact 完整特性的SQLite編譯出來在500KiB左右,裁剪特性甚至可以得到低於300KiB的庫(當前版本3.8.11.1)。
  • Manifest typing 可以宣告資料庫欄位型別,但是欄位儲存的型別實際的儲存型別和實際值相關,單獨的一個欄位可能包含不同儲存類的值。
  • Variable-length records 可變長度記錄,例如你儲存一個字元到VARCHAR(100) 的列,實際需要的儲存空間一個字元加一個位元組的儲存空間。
  • SQL statements compile into virtual machine code SQL語句會被編譯成虛擬機器程式碼,這種虛擬機器程式碼直白可讀,便於除錯。
  • Public domain 完全開源。
  • SQL language extensions

主要缺點

  • SQLite 只提供資料庫級的鎖定,所以不支援高併發。
  • 不支援儲存過程。
  • SQLite 沒有使用者帳戶概念,而是根據檔案系統確定所有資料庫的許可權。這會使強制執行儲存配額發生困難,強制執行使用者許可變得不可能。

如果只在移動裝置使用SQLite,那麼他的優點足夠好,並且缺點不明顯,所以大叔MySQL走開。SQLite妹妹快過來╭(╯3╰)╮。

事務與鎖( < 3.7.0)

SQLite的事務和鎖是很重要的概念。

SQLite有5個不同的鎖狀態

  1. UNLOCKED(未加鎖)
  2. SHARED(共享)
  3. RESERVED(保留)
  4. PENDING(未決)
  5. EXCLUSIVE(排它)

SQLite有一個加鎖表,記錄資料庫連線的鎖狀態。每個資料庫連線在同一時刻只能處於其中一個鎖狀態。每種狀態(UNLOCKED)都有一種鎖與之對應。

資料庫連線最初處於UNLOCKED狀態,在此狀態下,連線還沒有存取資料庫。當連線到了一個數據庫,甚至已經用BEGIN開始了一個事務時,連線都還處於UNLOCKED狀態。為了能夠從資料庫中讀取資料,連線必須必須進入SHARED狀態,也就是說首先要獲得一個SHARED鎖。多個連線可以同時獲得並保持共享鎖,也就是說多個連線可以同時從同一個資料庫中讀資料,SQLite是支援併發讀取資料的

一個連線想要寫資料庫,它必須首先獲得一個RESERVED鎖。一個數據庫上同時只能有一個RESERVED鎖,保留鎖可以與共享鎖共存,RESERVED鎖即不阻止其它擁有SHARED鎖的連線繼續讀資料庫,也不阻止其它連接獲得新的SHARED鎖。 一旦一個連接獲得了RESERVED鎖,它就可以將資料寫入緩衝區,而不是實際地寫到磁碟。 當連線想要提交修改(或事務)時,需要獲得PENDING鎖,之後連線就不能再獲得新的SHARED鎖了,但已經擁有SHARED鎖的連線仍然可以繼續正常讀資料庫。當所有其它SHARED鎖都被釋放時,擁有PENDING鎖的連線就可以將其鎖提升至EXCLUSIVE鎖,此時就可以將以前對緩衝區所做的修改寫到資料庫檔案。所以SQLite是不支援併發寫的

事務

SQLite有三種不同的事務

  1. DEFERRED(推遲)
  2. MMEDIATE(立即)
  3. EXCLUSIVE(排它)

事務型別在BEGIN命令中指定:

DEFERRED

一個DEFERRED事務不獲取任何鎖(直到它需要鎖的時候),BEGIN語句本身也不會做什麼事情——它開始於UNLOCK狀態。預設情況下就是這樣的,如果僅僅用BEGIN開始一個事務,那麼事務就是DEFERRED的,同時它不會獲取任何鎖;當對資料庫進行第一次讀操作時,它會獲取SHARED鎖;同樣,當進行第一次寫操作時,它會獲取RESERVED鎖。

MMEDIATE

由BEGIN開始的IMMEDIATE事務會嘗試獲取RESERVED鎖。如果成功,BEGIN IMMEDIATE保證沒有別的連線可以寫資料庫。但是,別的連線可以對資料庫進行讀操作;但是,RESERVED鎖會阻止其它連線的BEGIN IMMEDIATE或者BEGIN EXCLUSIVE命令,當其它連線執行上述命令時,會返回SQLITE_BUSY錯誤。這時你就可以對資料庫進行修改操作了,但是你還不能提交,當你COMMIT時,會返回SQLITE_BUSY錯誤,這意味著還有其它的讀事務沒有完成,得等它們執行完後才能提交事務。

EXCLUSIVE

EXCLUSIVE事務會試著獲取對資料庫的EXCLUSIVE鎖。這與IMMEDIATE類似,但是一旦成功,EXCLUSIVE事務保證沒有其它的連線,所以就可對資料庫進行讀寫操作了。

死鎖

如果兩個以BEGIN DEFERRED開始事務的連線都處於SHARED狀態,並且都在等待對方結束SHARED從而進入RESERVED的話,就會進入死鎖狀態。所以BEGIN DEFERRED開始的事務是有可能產生死鎖的.

Write-Ahead Logging ( >=3.7.0 )

SQLite 3.7.0之前是不支援寫的時候讀得。為了能夠讀得時候寫,引入了Write-Ahead Logging(WAL)機制,這樣可以支援一個寫和多個讀併發。

在引入WAL機制之前,SQLite使用rollback journal機制實現原子事務。

rollback journal機制的原理是:在修改資料庫檔案中的資料之前,先將修改所在分頁中的資料備份在另外一個地方,然後才將修改寫入到資料庫檔案中;如果事務失敗,則將備份資料拷貝回來,撤銷修改;如果事務成功,則刪除備份資料,提交修改。

WAL機制的原理是:修改並不直接寫入到資料庫檔案中,而是寫入到另外一個稱為WAL的檔案中;如果事務失敗,WAL中的記錄會被忽略,撤銷修改;如果事務成功,它將在隨後的某個時間被寫回到資料庫檔案中,提交修改。

同步WAL檔案和資料庫檔案的行為被稱為checkpoint(檢查點),它由SQLite自動執行,預設是在WAL檔案積累到1000頁修改的時候;當然,在適當的時候,也可以手動執行checkpoint,SQLite提供了相關的介面。執行checkpoint之後,WAL檔案會被清空。

在讀的時候,SQLite將在WAL檔案中搜索,找到最後一個寫入點,記住它,並忽略在此之後的寫入點(這保證了讀寫和讀讀可以並行執行);隨後,它確定所要讀的資料所在頁是否在WAL檔案中,如果在,則讀WAL檔案中的資料,如果不在,則直接讀資料庫檔案中的資料。

在寫的時候,SQLite將之寫入到WAL檔案中即可,但是必須保證獨佔寫入,因此寫寫之間不能並行執行。

WAL在實現的過程中,使用了共享記憶體技術,因此,所有的讀寫程序必須在同一個機器上,否則,無法保證資料一致性。

優點

  1. 讀和寫可以完全地併發執行,不會互相阻塞(但是寫之間仍然不能併發)。
  2. WAL在大多數情況下,擁有更好的效能(因為無需每次寫入時都要寫兩個檔案)。
  3. 磁碟I/O行為更容易被預測

缺點

  1. 訪問資料庫的所有程式必須在同一主機上,且支援共享記憶體技術。
  2. 每個資料庫現在對應3個檔案:.db,-wal,-shm。
  3. 當寫入資料達到GB級的時候,資料庫效能將下降。
  4. 3.7.0之前的SQLite無法識別啟用了WAL機制的資料庫檔案。
  5. WAL引入的相容性問題。在啟用了WAL之後,資料庫檔案格式的版本號由1升級到了2,因此,3.7.0之前的SQLite無法識別啟用了WAL機制的資料庫檔案。禁用WAL會使資料庫檔案格式的版本號恢復到1,從而可以被SQLite 3.7.0之前的版本識別。
  6. WAL引入的效能問題。在一般情況下,WAL會提高SQLite的事務效能;但是在某些極端情況下,卻會導致SQLite事務效能的下降。
    1. 在事務執行時間較長或者要修改的資料量達到GB級的時候,WAL檔案會被佔用,它會暫時阻止checkpoint的執行(checkpoint會清空WAL檔案),這將導致WAL檔案變得很大,增加定址時間,最終導致讀寫效能的下降。
    2. 當checkpoint執行的時候,會降低當時的讀寫效能,因此,WAL可能會導致週期性的效能下降

END