SQLSERVER的資料頁面結構
在論壇裡經常有人問到SQLSERVER是怎麽存放基礎資料表資料的,既然不想查MSDN,本人就在這裡說一下吧
基礎資料表資料都存放在資料頁裡面,SQLSERVER儲存資料都是按照“頁”為單位來存放在磁碟的,SQLSERVER從
磁碟讀寫資料也是按照 “頁” 為單位 一頁一頁地讀取到記憶體,所以有時候如果資料不能塞滿整個資料頁,那麼
這種情況就叫做:page split 頁面分割 或者 “片段”(詳細的在文章結尾會跟大家解釋一下因為要先瞭解SQLSERVR
的資料頁面結構才能解釋清楚) ,SQLSERVER有時候需要讀取兩頁才能把使用者需要找的資料讀出來
,如果表加了索引的話可以通過重建索引的方法解決,沒有建立索引的話就沒有辦法了
因為建立了索引的表,表裡面的資料是放在B樹資料結構的索引頁,而不是堆資料結構的資料頁
好像說太多了,現在說一下資料頁面是怎樣存放資料:
每一行資料在資料頁面裡是怎麽存放的?
結構組成:每個SQLSERVER的資料頁面大致分成3個部分:頁頭,頁尾位移量,資料存放區 這3個部分
假設現在有一個表,表的結構是:
CREATE TABLE test(
a INT,
b INT
)
他在1:100這個頁面上儲存資料(1是資料庫的資料檔案ID 亦即是FILEID,100 是PAGEID 頁面編號)。
這個頁面結構大致如
在頁頭部分,會記錄頁面屬性,包括頁面編號等,還會記錄當前頁面空閑部分的起始位置在哪裡
這樣SQLSERVER在要插入新資料的時候,就能夠很快地找到開始插入的位置,而頁尾的位移量
記錄了每一條資料行的起始位置。這樣SQLSERVER在找每一條記錄的時候,就能很快找到不會
把前一條記錄和後一條搞混。在圖例這一頁裡現在有兩條記錄:(1,100)和(2,200)第一條
記錄的開始位置是96,第二條記錄的開始位置是111,從126開始,是閒置空間
當頁面裡的資料行發生變化的時候,SQLSERVER不但要去修改資料本身,還要修改這些位移量的值,
以保證SQLSERVER能夠繼續準確地管理資料頁面裡的每一行
不知道大家明白不? 該睡覺了,加完班很困哦
2012-12-21補充:
開頭說了片段 頁面分割,如果有索引的話也叫“索引片段”,那麼這些片段是怎麽造成的 以及如何避免和修複呢?
造成的原因很簡單:當你刪除表裡一條記錄的時候,SQLSERVER會去找這條記錄的所在頁面
然後刪除,當你刪除了之後,那麼那個資料頁面存放的資料就變成不連續的了,這時候就稱為“資料片段”
就是頁面存放的資料不連續,當你刪除多條記錄,而這些記錄都在同一個頁面,那麼就會造成資料塞不滿
整個頁面,當你插入一條記錄的時候,這條記錄是不會插入到你上次刪除的那條記錄的地方的,如果SQLSERVER
的最後一個資料頁面(這些資料頁面是用雙向鏈表來連結的)有位置就插入去,沒有位置就新開一個頁面,然後插入
記錄
如果存在這些片段主要兩個弊端:
弊端一:SQLSERVER在尋找記錄的時候要尋找多個頁面才能找到那條記錄(特別使用表掃描執行計畫),SQLSERVER按一定順序
一條一條記錄地去找,這樣的話本來只需要讀取一個頁面到記憶體,SQLSERVER現在需要讀取兩個頁面到記憶體(特別SQLSERVER
使用表掃描執行計畫的時候),會造成記憶體的使用增大,尋找時間增多
弊端二:本來使用一個頁面可以存放下連續的資料,現在需要兩個頁面才能存放下這些資料,造成磁碟空間的浪費,佔用額外的
磁碟空間
如何避免和修複:
最好在表上建立一個叢集索引,然後通過重建索引或者重新組織索引的方式使資料重新按照建立索引的那個欄位的順序重新排序
儲存,重建索引會把這些資料頁面重新排序把沒有“塞滿資料”的頁面重新“塞滿”,並有序排列(更詳細的大家可以看一下MSDN)
看一下這些資料是如何按叢集索引的方式來有序存放的
MSDN:叢集索引除了可以提高查詢效能之外,還可以按需重建或重新組織來控製表片段。也可以對視圖建立叢集索引。
叢集索引基於資料行的索引值在表內排序和儲存這些資料行。每個表只能有一個叢集索引,因為資料行本身只能按一個順序儲存
只能按一個順序儲存是指:當你建立叢集索引或者主鍵的時候,你有可能在多個列上建立了叢集索引或者複合主鍵
SQLSERVER只會按照你建立索引的時候的最左一列的欄位來排序,只是一列,不是說先按第一列排序,
再按第二列排序,再按第三列排序。。。。。。
這個有很多人會混淆!!!!!!!!!!!!!!!
如果表格上沒有叢集索引那麼這個問題不能解決,沒有叢集索引的表都是堆資料結構的表,就是說資料本身就沒有一個相片順序
除非加一個叢集索引,使資料有序排列,非叢集索引也不能解決因為非叢集索引只是在表上加了索引但是資料還是按照“堆”
資料結構來排列的,因為SQLSERVER的頁面類型有索引頁面,資料頁面,LOB頁面,行溢出頁面,具體大家可以看一下
我之前寫的這篇文章:SQLSERVER的Table Store組織圖
http://www.cnblogs.com/lyhabc/archive/2012/09/20/2695818.html
可以參考的MSDN文章:
叢集索引設計指南
http://msdn.microsoft.com/zh-cn/library/ms190639(v=SQL.100).aspx
建立叢集索引
http://msdn.microsoft.com/zh-cn/library/ms186342.aspx
建立非叢集索引
http://msdn.microsoft.com/zh-cn/library/ms179325(v=SQL.100).aspx
非叢集索引設計指南
http://msdn.microsoft.com/zh-cn/library/ms189280.aspx
所以很多書上面都說一個資料量比較大的表最好建立一個叢集索引其實也是有道理的