SQLite數據庫的工作原理

SQLite數據庫的工作原理

介紹

數據庫是構建軟件系統的重要組成部分,用於有效地存儲和讀取數據。在這裡,我們將使用早期版本的SQLite來討論數據庫實現的一些體系結構細節。

SQLite是一個小型數據庫應用程序,用於數百萬個軟件和設備。SQLite是由D.Richard Hipp於2000年8月發明的。SQLite是一個高性能,輕量級的關係數據庫。如果你願意在編碼級別學習數據庫的內部原理,那麼SQLite是最好的開源數據庫,具有高度可讀的源代碼和大量文檔。閱讀更高版本的SQLite變得有點困難,因為它包含許多新功能。為了理解數據庫內部的基本實現,對數據結構的理解會顯得比較重要,計算機理論以及操作系統的工作原理也要有一定的瞭解。

在這裡,我們將討論SQLite 2.5.0版本。大家可以在GitHub上找到 SQLite後端的簡單實現。

為什麼使用數據庫

將數據保存在平面文件中並不能有效地讀取和存儲數據。數據庫按正確順序組織數據,以便數據讀取和寫入速度更快。數據可以是結構化的,半結構化的或非結構化的。數據庫主要用於存儲結構化和半結構化數據。可以根據要存儲的數據結構的類型,按如下方式調度數據庫。

  1. 關係數據庫:常用的數據庫類型,具有表結構。表可以與其他表有關係。用於處理此類數據庫上的數據的SQL語言。
  2. 鍵值數據庫:存儲的數據以及與之關聯的鍵。可以使用給定密鑰檢索數據。內存數據庫通常被定義為這種類型的數據庫。
  3. 對象數據庫:數據結構更像是對象而不是表。
  4. 圖形數據庫:圖形數據庫是主要用於數據挖掘和社交媒體應用程序的節點和邊緣的集合。

SQLite數據結構

SQLite數據庫體系結構分為兩個不同的部分,分別命名為核心和後端。核心部分包含接口,令牌生成器,分析器,代碼生成器和虛擬機,它們為數據庫事務創建執行順序。後端包含訪問文件系統的B樹和OS接口。Tokenizer,Parser和代碼生成器共同命名為編譯器,它生成一組在虛擬機上運行的操作碼。

從哪裡開始

要了解數據庫的體系結構,需要具備以下先決條件。

  1. 很好地理解數據結構和算法。特別是B樹,鏈表,Hashmaps等數據結構。
  2. 對計算機體系結構有所瞭解如何讀寫磁盤,分頁和緩存如何工作。
  3. 計算機理論,如有限自動機,Context Free Grammer和一些正則表達式知識。

SQLite架構

VFS(虛擬文件系統)

Unix和Windows上的文件訪問權限彼此不同。VFS提供了訪問文件的通用API,而不考慮其運行的操作系統的類型。此API包括打開,讀取,寫入和關閉文件的功能。以下是VFS中用於讀取,將數據寫入文件的一些API。


/ *
創建文件連接以進行讀寫
zFilename:文件名
id:文件指針
pReadonly:讀或寫
* /
int sqliteOsOpenReadWrite(const char * zFilename,OsFile * id,int * pReadonly);

/ *
獲取鎖定以讀取文件。這個功能應該是
在調用任何文件讀取函數之前調用。

如果成功則返回0
id:文件指針
* /
int sqliteOsReadLock(OsFile * id);

/ *
獲取寫鎖定以寫入文件。之前應調用此函數
對文件系統執行任何寫入操作。
如果成功則返回0
id:文件指針
* /
int sqliteOsWriteLock(OsFile * id);

/ *
移動到給定數量的offest以讀取或寫入文件
* /
int sqliteOsSeek(OsFile * id,int offset);

/ *
從sqliteOsSeek指向的偏移量中讀取文件中的amt字節
* /
int sqliteOsRead(OsFile * id,void * pBuf,int amt);

/ *
將ptf中的amt字節寫入文件
* /
int sqliteOsWrite(OsFile * id,const void * pBuf,int amt);

在這裡,我們可以使用sqliteOpenReadWrite函數開始使用文件。此函數為我們提供指向文件的指針,該文件可用於讀取或寫入數據。接下來,應在執行任何讀寫操作之前獲取鎖。如果它只是一個讀操作,則應獲取讀鎖定。應該為讀取和寫入事務獲取寫鎖定。

然後可以通過將文件的偏移量提供到sqliteOsSeek函數中來尋找位置來完成讀寫操作。偏移量是從文件起始點到數據應寫入或讀取的位置的字節數。

頁是文件系統上數據庫事務的最小單位。當數據庫需要從文件中讀取數據時,它會將其作為頁請求。將頁加載到數據庫引擎後,如果頁在其緩存上頻繁訪問,則可以存儲該頁。頁編號從一開始。第一頁稱為根頁。頁的大小是不變的。

/ *
打開具有給定文件名的尋呼機
* /
int sqlitepager_open(Pager ** ppPager,const char * zFilename,int nPage,int nEx);

/ *
獲取頁碼指定的頁面
* /
int sqlitepager_get(Pager * pPager,Pgno pgno,void ** ppPage);

/ *
開始將數據寫入pData中指定的頁面
* /
int sqlitepager_write(void * pData);


/ *
將頁面更改提交到文件中
* /
int sqlitepager_commit(Pager *);


/ *
關閉與文件的連接
* /
int sqlitepager_close(Pager * pPager);

B樹

B樹是一種數據結構,用於根據數據的值將數據存儲為樹。最簡單的B樹形式是二叉樹。數據庫使用B樹數據結構來存儲索引以提高數據庫的性能。B樹的每個節點都包含用於索引的鍵列表。可以為表中的每個列創建B樹索引。每個B樹都有根頁面,這是任何B樹搜索的起點。

要在B樹上指向一行,使用稱為“Cursor”的特殊指針。光標用於指向以頁面ID和偏移量idx給出的記錄。SQLite在表上存儲數據庫模式,稱為“master_table”。master_table始終存儲在數據庫的第一頁上。



/ *
打開與zFileName指定的頁面文件名的文件連接
nCache大小緩存
* /
int sqliteBtreeOpen(const char *zFilename, int mode, int nCache, Btree **ppBtree)


/ *
開始交易。在任何btree修改之前應該調用此函數
操作
* /
INT sqliteBtreeBeginTrans(Btree * PBT)



/ *
插入帶有nKey字節的鍵pKey和帶有nData字節的值pData
進入Btree
* /
int sqliteBtreeInsert(BtCursor * pCur,const void * pKey,int nKey,
const void * pData,int nData)


/ *
將數據寫入文件
* /
INT sqliteBtreeCommit(Btree * PBT)

/ *
使用nKey字節將光標移動到匹配的pKey
* /
int sqliteBtreeMoveto(BtCursor * pCur,const void * pKey,int nKey,int * pRes)

VDBE(虛擬數據庫引擎)

VDBE是一個運行一組操作的虛擬機,由代碼生成器生成。所有SQL命令(包括insert,delete,update,select)都轉換為一組操作碼,然後在虛擬機上運行。每個操作碼包含三個輸入。我們可以將此輸入視為函數的輸入。

編譯器

符號標識器(Tokenizer),語法解析器和代碼生成器在一起稱為編譯器,它生成在VBDE上運行的操作碼集。Tokenizer通過掃描SQL代碼生成一組令牌。然後,它驗證語法並生成解析樹。Lemon解析器用於通過預定義的Context Free Grammer解析給定的SQL代碼。代碼生成器將此解析樹轉換為使用SQLite操作碼編寫的迷你程序。

結論

SQLite是一個簡單,輕量級,高性能的關係數據庫,廣泛用於軟件設計。Eite版本的SQLite是用簡單的架構和高度可讀的代碼編寫的。頁面提供了一個抽象層,可以將數據作為固定大小的塊讀寫到文件系統中。而Btree提供了一種以內存方式存儲數據的方法,可以更快地訪問數據。當SQL進入SQLite時,它將SQL轉換為SQLite機器代碼並在VBDE上運行它。結果通過API發回給用戶。

經過這一系列的過程,不知道大家對SQLite是否具備了一定的瞭解,當然如果想完全搞懂,還是得鑽研進去才行,但是作為談資跟人聊一聊應該是足夠使用了。


分享到:


相關文章: