SQLite中的B-Tree實現細節分析

來源:互聯網
上載者:User

SQLite在儲存在外部的資料庫是以B-Tree來組織的。關於B-tree的細節,參考
**
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
** "Sorting And Searching", pages 473-480. Addison-Wesley
** Publishing Company, Reading, Massachusetts.
**
基本思想是檔案包含的每一頁都包括N個資料庫入口和N+1個指向子頁的指標。檔案分成很多頁儲存。為什麼這麼幹,因為記憶體分頁管理機制鬧得。外存中每個頁就是B樹的一個節點。
----------------------------------------------------------------
| Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
----------------------------------------------------------------
Ptr(0)指向的頁上的所有的key的值都小於Key(0)。所有Ptr(1)指向的頁和子頁的所有的key的值都大於Key(0),小於Key(1)。所有Ptr(N)指向的頁和子頁的key的值都大於Key(N-1),等等。

為了知道一個特定的key,需要從磁碟上以O(long(M))來讀取,其中M是樹的階數。記憶體中找不到了,就發生缺頁中斷。
主要是解決記憶體中找不到的問題。一方面換出來一些。一方面換進去一些。換進去的時候要找到他們再硬碟的哪個頁面上啊。
(B樹的優點就是適合於用塊兒儲存的存放裝置上。)利用所以,可以知道他們們在哪個頁面上。

在SQLite的實現中,一個檔案可以含有1個或的過獨立的BTree。每一個BTree由它的根頁的索引來標識。所有入口的key和資料群組成了有效負荷(payload)。資料庫的一頁有一個固定的有效負荷總量。如果負荷大於了預先設定的值,那麼剩餘的位元組就會被儲存在溢出頁上。一個入口的有效負荷再加上前向指標(the preceding pointer)構成了一格(cell)。每一頁都有一個小頭部,包含了Ptr(N)指標和其它一些資訊,例如key和資料的大小。

格式細節
一個檔案分成了多個頁。第一頁叫做頁1,第二頁叫做頁2,一次類推。頁的個數為0表示沒有頁。頁的大小可以從512 到 65536。每一頁或者是一個btree頁,或者是一個freelist頁,或者是一個溢出頁。
第一頁一定是一個btree頁。第一頁的前面100個位元組包含了一個特殊的首部(檔案頭),它是這個檔案的描述。
檔案頭的個數如下:
** OFFSET SIZE DESCRIPTION
** 0 16 Header string(首部字串): "SQLite format 3\000"
** 16 2 Page size in bytes(頁的位元組數).
** 18 1 File format write version(檔案寫操作的版本)
** 19 1 File format read version (檔案讀操作的版本)
** 20 1 Bytes of unused space at the end of each page(每一頁結尾未使用的位元組)
** 21 1 Max embedded payload fraction(最大的嵌入有效負荷分區)
** 22 1 Min embedded payload fraction(最小的嵌入有效負荷分區)
** 23 1 Min leaf payload fraction(最小的頁有效負荷分區)
** 24 4 File change counter (檔案變化計數器)
** 28 4 Reserved for future use (保留位元組)
** 32 4 First freelist page (第一個freelist頁)
** 36 4 Number of freelist pages in the file (本檔案中freelist頁的個數)
** 40 60 15 4-byte meta values passed to higher layers()
**
所有的整數都是大端的。

每次修改檔案時,檔案變化計數器都會增加。這個計數器可以讓其他進程知道何時檔案被修改了,他們的cache是否需要清理。

最大嵌入有效負荷分區是一頁的所有可用空間,被標準B-tree(非葉資料)表的單獨的一個所能使用的總量。值255代表100%。預設情況下,一格(cell)的最大量被限制為,至少有4格才能填滿一頁。因此,預設的最大嵌入負荷分區是64。

如果一頁的有效負荷大於了最大有效負荷,那麼剩下的資料就要被儲存到溢出頁。一旦分配了一個溢出頁,有可能會有許多資料也被轉移到這個溢出頁,但是不會讓格cell的大小小於最小嵌入有效負荷分區的。

最小頁有效負荷分區與最小嵌入有效負荷分區類似,但是它是應用於LEAFDATA tree中的分葉節點。一個LEAFDATA的最大有效負荷分區為100%(或者是值255),它不用再首部指定。

BTree的每一頁被分為三部分:首部,格(cell)指標數組,和格cell的內容。頁1還會在頁首部有100位元組的檔案頭。
**
** |----------------|
** | file header | 100 bytes. Page 1 only.
** |----------------|
** | page header | 8 bytes for leaves. 12 bytes for interior nodes
** |----------------|
** | cell pointer | | 2 bytes per cell. Sorted order.
** | array | | Grows downward
** | | v
** |----------------|
** | unallocated |
** | space |
** |----------------| ^ Grows upwards
** | cell content | | Arbitrary order interspersed with freeblocks.
** | area | | and free space fragments.
** |----------------|
**
頁首部如所示:
**
** OFFSET SIZE DESCRIPTION
** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
** 1 2 byte offset to the first freeblock
** 3 2 number of cells on this page
** 5 2 first byte of the cell content area
** 7 1 number of fragmented free bytes
** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
**
標誌位定義了這個BTree頁的格式。葉leaf標誌意味著這一頁沒有孩子children。zerodata0資料表示這一頁只含有key,沒有資料;intkey標誌意味著key是一個整數,而且是被儲存在格cell首部的key大小處,而不是在有效負荷地區。

格cell指標數組從頁首部開始。格cell指標數組包含0個或多餘2個位元組的數字,這個數字代表格cell內容地區中的格cell內容從檔案起始位置的位移量。格cell指標式有序的。系統儘力保證空閑空間位於最後一個格cell指標之後,這樣可以保證新的格cell可以很快的添加,而不用重新整理(defragment)這一頁。

格cell內容儲存在頁的末尾,且是向檔案的起始方向增長。

在格cell內容地區中的未使用的空間被收集到鏈表freeblocks上。每一個freeblock至少有4個位元組。第一個freeblock的位移在頁首部給出了。Freeblock是增序的。因為一個freeblock至少有4個位元組,所有在格cell內容地區的3個或是哦啊與3個的未用空間不能存在於freeblock鏈表上。這些3個或少於3個的空閑空間被稱為片段。所有片段的總個數被記錄下來,儲存於頁首部的位移7的位置。

** SIZE DESCRIPTION
** 2 Byte offset of the next freeblock
** 2 Bytes in this freeblock
**

格cell是可變長度的。格cell被儲存於頁的末尾格cell內容地區。指向格cell的cell指標數組緊跟在頁首部的後面。格cell不必是連續或者有序的,但是格cell指標是連續和有序的。

格cell內容充分利用了可變長度整數。可變長度整數是從1到9個位元組,每個位元組的低7位被使用。整個整數由8位的位元組組成,其中第一個位元組的第8位被清零。整數最重要的位元組出現在第一個。可變長度整數一般不多於9個位元組。作為一種特殊情況,第九個位元組的所有8個位元組都會被認為是資料。這就允許了64位整數變編碼為9個位元組。
** 0x00 becomes 0x00000000
** 0x7f becomes 0x0000007f
** 0x81 0x00 becomes 0x00000080
** 0x82 0x00 becomes 0x00000100
** 0x80 0x7f becomes 0x0000007f
** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
本篇文章來源於 Linux公社網站(www.linuxidc.com) 原文連結:http://www.linuxidc.com/Linux/2012-11/75009.htm

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.