儲存引擎揭秘 基本結構之一 記錄

2021-08-25 10:52:02 字數 4755 閱讀 7682

儲存引擎揭秘:基本結構之一——記錄

本週我將發表一系列 sql server 中用來儲存資料和跟蹤分配的基本結構。大部分文章其實當初我在 teched2006 上開博時便發表過,但是現在我想更清晰地描述它,並使用 dbcc page 來檢查各種結構。

那麼,什麼是記錄?簡單地說,一條記錄就是物理儲存的表或索引的一行。當然,實際上比這複雜得多 …

資料記錄

堆和聚集索引的存放的列之間的不同,我以後專門寫文章說。(譯註:非唯一聚集索引中若鍵相同,系統會自動在最後增加乙個 4 位元組的唯一識別符號列)

被前轉記錄(forwarded/前轉記錄(forwarding)

索引記錄

文字記錄

幽靈記錄

其他記錄型別

記錄的結構

不管什麼型別及用途,所有的記錄都有相同的結構,只是列的數量和型別有所不同而已。比如,乙個有著複雜架構的表可能有著上百個不同型別的列而乙個分配位圖只有乙個列,充滿整個頁。

記錄結構如下:

記錄的固長部分,包含所有固長資料型別列(比如, bigint, char(10), datetime )

null 位圖

變長列的偏移陣列

版本標誌

null位圖優化

為什麼說可通過 null 位圖優化呢?

首先,使用 null 位圖可以省略為定長資料型別的儲存特殊的「 null 」值。如果沒有 null 位圖,你怎麼能知道一列是否為 null 值呢?對於定長列,你得定義乙個特殊的「 null 」值,這將限制定長型別的有效範圍。對於 varchar 列,它的值可能是 0 長度的空字串,所以通過檢查列長度並不管用——你必須也定義特殊的「 null 」值;當然其他變長型別可以通過檢查長度來判斷是否為 null 值。總之,我們需要 null 位圖。

其次,它可以節省 cpu 週期。如果沒有 null 位圖,就必須為定長和變長列執行額外的指令。

對定長列:

讀取儲存的列值(可能會有一次 cpu 的 cache miss (快取記憶體預設))

取出為這個型別預定義的「 null 」值。(可能會有一次 cpu 的 cache miss ,但是在多行讀取中只有第一次讀時會發生)

在上面取出兩個值之間進行比較

對變長列:

計算出變長陣列的偏移

讀出變長列的數目(可能會有一次 cpu 的 cache miss )

計算需要讀取的變長偏移陣列的位置

讀取列的偏移值(可能會有一次 cpu 的 cache miss )

將下一列的偏移值也讀出(如果 4 的偏移正好是快取邊界,可能會有另一次 cpu 的 cache miss )

比較兩值是否相等

但是如果有 null 位圖,你只要做下面的事情就行了:

讀取 null 點陣圖的偏移(可能會有一次 cpu 的 cache miss )

計算出你要讀取的 null 位的附加的偏移(你要讀的列對應的位)

讀出它(可能會有一次 cpu 的 cache miss )

所以這和查詢了乙個定長列差不多,但是對於變長列和多行查詢來說, null 點陣圖的優勢是非常明顯的。

使用dbcc inddbcc page詳細檢查一條資料

先建立乙個用來查詢的例子表:

usemaster;go

ifdatabaseproperty(n

'recordanatomy'

,'version'

)>

0 drop

database

recordanatomy;go

create

database

recordanatomy;go

userecordanatomy;go

create

table

example

(destination varchar

(100

), activity varchar

(100

), duration int

);go

insert

into

example

values

('banff'

,'sightseeing',5

);insert

into

example

values

('chicago'

,'sailing',4

);go

使用 dbcc ind 來獲得需要檢視的頁:

dbcc

ind(

'recordanatomy'

,'example',1

);go

輸出顯示資料頁是( 1:143 ),我們我們將使用 dbcc page 來列出該頁,使用選項 3 可以完整列出每一條記錄。

dbcc

traceon

(3604

);go

dbcc

page

('recordanatomy',1

,143,3

); go

記住我們需要開啟跟蹤標誌以便讓 dbcc page 輸出結果至控制台而不是錯誤日誌裡。輸出結果大致如下:

slot 0 offset 0x60 length 33

record type = primary_record record attributes = null_bitmap variable_columns

memory dump @0x5c76c060

00000000: 30000800 05000000 0300f802 00160021 †0..............!

00000010: 0042616e 66667369 67687473 6565696e †.banffsightseein

00000020: 67†††††††††††††††††††††††††††††††††††g

slot 0 column 0 offset 0x11 length 5

destination = banff

slot 0 column 1 offset 0x16 length 11

activity = sightseeing

slot 0 column 2 offset 0x4 length 4

duration = 5

讓我們使用上面我列出的記錄結構來看看這些結構是如何儲存的:

在我們的例子中,沒有置任何位,這表示這記錄是個主記錄。如果記錄是索引記錄,位元組 0 的值為 0x36 。記住記錄型別是從位 1 開始的,而不是位 0 。所以上面的列舉出的記錄型別值需要向左移一位(即乘以 2 )才能獲得位元組中的值。

位元組 1 是記錄元資料的 tagb 位元組。它可以是 0x00 或者 0x01 。如果是 0x01 ,則表示記錄型別是幽靈向前記錄;如果是 0x00 ,則表示我們期望 taga 位元組。

位元組 2 和 3 是記錄中 null 點陣圖的偏移。這裡是 0x0008 ,表示從第 4 個位元組開始的固定長度部分為 4 位元組。因為我們知道表架構,所以這是我們期望的結果。

位元組 4 至 7 是定長部分。再一次,因為我們知道表的架構,所以我們知道它是乙個 4 位元組的整數。如果不知道架構的話,你就只好猜了。這個值是 0x00000005 ,這就是我們想看到的列的值。

位元組 8 和 9 是記錄中列的數目。這裡 0x0003 是正確的。這表示有 3 列,每列 1 位的 null 位圖占用 1 個位元組。

位元組 10 為 null 位圖。這裡值是 0xf8 ,我們想把它變成二進位制看看它值的意義。 0xf8

= 11111000

. 這就有意義了。位 0-2 代表列 1-3 ,都是 0 ,表示這些列都不是 null 值。位 3-7 表示不存在的列,它們被置為 1 。

位元組 11 和 12 是記錄中變長列的數目。這裡值是 0x0002 ,我們知道這是正確的。這表示有在變長列偏移陣列中 2 個兩位元組條目:位元組 13-14 中值為 0x0016; 位元組 15-16 中值為 0x0021 。記住 null 位圖條目指向的列值的尾部——這樣我們就知道每個列有多長,而不需要專門儲存列長度。

最後的偏移是位元組 15 和 16 ,這表示第乙個變長列的開始偏移為 17 (或 16 進製 0x11 ),這和 dbcc page 輸出一致。第 1 個變長列結束位元組是 0x16 ,所以第乙個變長列(從位元組 17 至 21 )的值為 0x42616e6666 。我們從表元資料中得知只是第乙個 varchar 列 destination 。轉換成 ascii 就是「 banff 」。同理,第二個變長列(從位元組 22 至 32 )的值為「 sightseeing 」,這和我們期望值是相同的。

分析至此。

sql server 2008 的一些特性會改變一些的記錄結構。

儲存引擎揭秘 基本結構之三 區

儲存引擎揭秘 基本結構之三 區 正文 前面的文章我介紹了資料檔案中的頁,包括頁結構和一些頁型別。現在我想解釋一下頁是如何組織成區 extent 的。乙個區是由資料檔案中 8個連續的頁組成。區從資料檔案頭部開始,並且總是 64k對齊 即 8頁對齊 區及其屬性在 sql server 2000 和200...

儲存引擎揭秘 基本結構之二 頁

儲存引擎揭秘 基本結構之二 頁 繼續儲存引擎揭秘系列,今天討論頁結構。頁是用來儲存記錄的。乙個頁是資料庫檔案中的乙個 8192 位元組段。頁在資料檔案中開始於 0位元組,並按 8192 位元組對齊。下面是乙個頁的基本結構圖 頁頭部 頁頭部大小為 96位元組。在這部分我最想做的事是使用 dbcc pa...

Tair儲存引擎之一Leveldb中資料的儲存思想

tair 是 自己開發的乙個分布式 key value 儲存引擎.tair 分為持久化和非持久化兩種使用方式.非持久化的 tair 可以看成是乙個分布式快取.持久化的 tair 將資料存放於磁碟中.在最新版本的tair trunk中目前實現了以下4種儲存引擎。非持久化 mdb 持久化 fdb kdb...