前文
本篇會跟大家對於SQL-Server資料表深入淺出的介紹.
關於子頁層
資料會存在子頁層中(page),一個Page大小為 8K/Page => 8092(8060 bytes)
每個Page除了存取資料還會存放一些
MetaData,我們可以先當作是每個Page大小是8K
Heap資料表
如果一張資料表沒有Clustered Index就會為Heap資料表,這意味著Heap資料表的資料不會有排序一直把資料新增進資料表中,Heap資料表Insert資料快
適合使用在Log資料表、Event資料表、稽核資料表….一直新增資料但比較少查詢表
IAM(index allocation map)
當Heap資料表要搜尋資料SQL-Server透過IAM(index allocation map)去尋要掃描Page範圍,因為IAM會以範圍存在於檔案中的順序來表示它們,這代表循序的堆積掃描都將依檔案順序進行。
使用IAM分頁設定掃描順序也表示堆積中的資料列通常不會依插入順序傳回
IAM Page在讀取資料的示意圖
可以看到讀取Page中資料順序和新增資料順序不一樣.

forwarding pointer
假如在Heap資料表更新欄位資料,就可能會造成forwarding pointer
製造forwarding pointer是因為原本Page塞不下更新後資料就會先把資料搬到另一個新建立Page上並在原本Page建立一個類似指標東西指向它.
這個指標會存在原本的Page大小是16 byte

forwarding pointer(Demo)
一個Page大小是8k
我們建立一個ForwardingPointers資料表,並且新增3筆資料進去
其中有一筆資料
replicate('2',7800)佔據78xxBytes.
| 1 | create table dbo.ForwardingPointers | 
新增完後我們利用DMV查詢目前ForwardingPointers使用的Page數量可以看到只使用一頁
因為目前資料大小可以放在同一個Page
| 1 | select page_count, avg_record_size_in_bytes, avg_page_space_used_in_percent | 

我們將dbo.ForwardingPointers另外兩個Val IS NULL更新成replicate('2',7800)
| 1 | UPDATE dbo.ForwardingPointers | 
再查詢一次dbo.ForwardingPointers使用Page,能發現已經使用了3個Page(因為已經觸發forwarding pointer)
已經把這次更新的資料搬到新Page上,因為更新後的資料大小已經超過目前Page可以負擔的大小

RID Lookup
在資料庫索引深入淺出(一)有說,資料表沒有Clustered Index且使用Index所有查詢欄位不包含在Converting Index中就會透過RID Lookup查找確切Page上的Row(藉由Row-Id)
此資料表是
Heap資料表在NonClustered Index中會存放Heap RID

記得在
DBCC IND取得的PID是要找PageType = 2
| 1 | DBCC traceon (3604); | 
透過DBCC可以看到查找資料表Page資料可以顯示如下結果集.
如果是Heap資料表會有一個欄位是Heap RID(Key)欄位.
HEAP RID:0x40110F0001002900
大小 8 bytes
- FID(2 bytes)
- PID(4 bytes)
- SLOT(2 bytes)
可藉由下面的Script來拆解Heap RID(Key)資料
| 1 | --轉換RID為 FID:PID:slot格式 | 
透過上面Script我們可以得到1:987456:41
我們在透過
| 1 | DBCC PAGE(AdventureWorks2012_Data,1,987456,3) | 
就可以查找到我們要的資料在PID = 987456這個Page中.
dbcc page 語法
下面語法透過dbcc page可以了解資料表存取資訊
| 1 | /* 建立測試資料表 */ | 
PageType – the page type. Some common ones are:
- 1 – data page
- 2 – index page
- 3 and 4 – text pages
- 8 – GAM page
- 9 – SGAM page
- 10 – IAM page
- 11 – PFS page
| 1 | dbcc traceon (3604); | 
- 第一個參數是數據庫名或數據庫ID。
- 第二個參數是數據庫中的對象名或對象ID,對象可以是表或者索引視圖。
- 第三個參數是一個非聚集索引ID或者 1, 0, 1, or 2. 值的含義:- 0: 只顯示對象的in-row data頁和 in-row IAM 頁。
- 1: 顯示對象的全部頁, 包含IAM 頁, in-row數據頁, LOB 數據頁row-overflow 數據頁 . 如果請求的對象含有聚集所以則索引頁也包括。
- -1: 顯示全部IAM頁,數據頁, 索引頁 也包括 LOB 和row-overflow 數據頁。
- -2: 顯示全部IAM頁。
 
__此文作者__:Daniel Shih(石頭)
__此文地址__: https://isdaniel.github.io/dbtable/ 
__版權聲明__:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!
