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的表格存儲組織結構
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
所以很多書上面都說一個數據量比較大的表最好建立一個聚集索引其實也是有道理的
-------------------------------------------------------------------------------------
2013-8-17 補充:
在正常的數據頁上,數據行緊接着頁的標頭按順序放置。頁的末尾是行偏移量表,對於頁中的每一行,每個行偏移表都包含一個條目。
每個條目記錄對應行的第一個字節與頁首的距離。行偏移表中的條目與頁中行的順序相反