以下測試基于版本:SQL SERVER 2008
很多同行會問起頁拆分的相關的問題,自己對頁拆分頁迷迷糊糊,有點云里霧里的感覺,今天來測試測試。
首先生成測試數據
--=========================================--使用TestDB數據庫來測試USE TestDBGODROP TABLE TB01GO--=======================================--創建測試表TB01CREATE TABLE TB01( ID INT PRIMARY KEY, C1 NVARCHAR(MAX))GO--=======================================--插入420條數據,所有數據存放在一個8KB的數據頁中INSERT INTO TB01(ID,C1)SELECT T.RID,N'C' FROM (SELECT ROW_NUMBER()OVER(ORDER BY object_id) AS RID FROM sys.all_columns) AS TWHERE T.RID<422AND T.RID<>418--====================================
現在表TB01上有一個數據頁(接近填滿),使用DBCC查看
然后嘗試插入數據導致頁拆分:
--====================================--插入一行數據INSERT INTO TB01(ID,C1)SELECT 418,REPLICATE(N'1',4000)--====================================--查看數據頁DBCC IND('TestDB','TB01',1)
我們可以很清楚地發現,在插入一行數據后,數據頁由原來的一頁變成了9頁(一個非葉子節點頁和8個葉子節點頁),是不是很不科學呢? 新插入的數據只需要一個數據頁來存放,加上原來的數據,只需要2個數據庫便可以存放,為什么會造成這么多頁面使用呢?
通過上面的圖,可以清楚看到數據有兩層,非葉子節點(也是根節點)頁是5170,使用該頁來查看數據分布情況:
--===================================--查看非葉子節點來查看數據和頁的對應情況DBCC PAGE('TestDB',1,5170,3)
觀察上圖的ID,我們可以發現以下規律
211=1+420/2
316=211+420/2/2
368=316+420/2/2/2
394=368+420/2/2/2/2
407=394+420/2/2/2/2/2
從上面的數據不難看出,每頁數據逐漸一半一半地減少。再通過sys.fn_dblog(NULL,NULL)來查看事務,最后一次插入操作引發1次插入事務和8個頁拆分事務。
由此,我們推斷出在上面的插入過程中,發生了以下操作:
1. 新事務開始,一行新數據需要插入到數據頁中,該數據行不是數據頁最尾數據行
2. 判斷頁中剩余空間,發現數據頁不能存放新插入行,需要頁拆分
3. 開啟一個新事務,將頁中一半數據移動到一個新的頁面,關閉事務
4. 循環第2步和第3步,直到有一數據頁能存放新插入的行
5. 插入數據,提交事務
到此,很多人就會疑問,拆分一半到底是數據行數的一半還是數據占用空間大小的一半呢?
讓我們再做一個實驗
--==========================================--清除表中數據TRUNCATE TABLE TB01--=======================================--插入198條數據,所有數據存放在一個8KB的數據頁中--前99條數據和后99天數據的大小不相同INSERT INTO TB01(ID,C1)SELECT T.RID,N'C' FROM (SELECT ROW_NUMBER()OVER(ORDER BY object_id) AS RID FROM sys.all_columns) AS TWHERE T.RID<100INSERT INTO TB01(ID,C1)SELECT T.RID,N'CCCCCCCCCCCC' FROM (SELECT ROW_NUMBER()OVER(ORDER BY object_id) AS RID FROM sys.all_columns) AS TWHERE T.RID>100AND T.RID<200--====================================--插入一行數據導致頁拆分INSERT INTO TB01(ID,C1)SELECT 100,REPLICATE(N'1',2000)
同樣適用根節點來數據分布:
由于后99行數據占用的空間大小較大,在頁拆分時,沒有將后99條全部拆分到新的數據頁上,因此我們得出結論,頁拆分時是按照數據占用空間大小來拆分的,與數據行數無關。
--=====================================================================================================
總結:
1.發現在頁拆分時,會按照頁中數據占用空間的情況,將占用空間一半的數據移動到新的數據頁上
2.如果拆分后仍無法存放新數據,則繼續頁拆分,知道有數據頁可以存放新數據為止,因此一次插入操作可能會引起多次頁拆分。
3.每次頁拆分會被當成一個事務處理,頁拆分的事務單獨提交(在提交插入事務之前已提交),及時插入失敗,頁拆分的事務也不會回滾。
4.更新導致的頁拆分情況與插入導致的頁拆分類似
PS:
1.在測試中,未發現沒有按照一半空間拆分的情況,但沒有找到相關官方文檔來證明。
--===========================================================================================================
小倉優子,各位大神應該知道的,不用我多說吧。吼吼
新聞熱點
疑難解答