以下測(cè)試基于版本:SQL SERVER 2008
很多同行會(huì)問(wèn)起頁(yè)拆分的相關(guān)的問(wèn)題,自己對(duì)頁(yè)拆分頁(yè)迷迷糊糊,有點(diǎn)云里霧里的感覺(jué),今天來(lái)測(cè)試測(cè)試。
首先生成測(cè)試數(shù)據(jù)
--=========================================--使用TestDB數(shù)據(jù)庫(kù)來(lái)測(cè)試USE TestDBGODROP TABLE TB01GO--=======================================--創(chuàng)建測(cè)試表TB01CREATE TABLE TB01( ID INT PRIMARY KEY, C1 NVARCHAR(MAX))GO--=======================================--插入420條數(shù)據(jù),所有數(shù)據(jù)存放在一個(gè)8KB的數(shù)據(jù)頁(yè)中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--====================================
現(xiàn)在表TB01上有一個(gè)數(shù)據(jù)頁(yè)(接近填滿),使用DBCC查看
然后嘗試插入數(shù)據(jù)導(dǎo)致頁(yè)拆分:
--====================================--插入一行數(shù)據(jù)INSERT INTO TB01(ID,C1)SELECT 418,REPLICATE(N'1',4000)--====================================--查看數(shù)據(jù)頁(yè)DBCC IND('TestDB','TB01',1)
我們可以很清楚地發(fā)現(xiàn),在插入一行數(shù)據(jù)后,數(shù)據(jù)頁(yè)由原來(lái)的一頁(yè)變成了9頁(yè)(一個(gè)非葉子節(jié)點(diǎn)頁(yè)和8個(gè)葉子節(jié)點(diǎn)頁(yè)),是不是很不科學(xué)呢? 新插入的數(shù)據(jù)只需要一個(gè)數(shù)據(jù)頁(yè)來(lái)存放,加上原來(lái)的數(shù)據(jù),只需要2個(gè)數(shù)據(jù)庫(kù)便可以存放,為什么會(huì)造成這么多頁(yè)面使用呢?
通過(guò)上面的圖,可以清楚看到數(shù)據(jù)有兩層,非葉子節(jié)點(diǎn)(也是根節(jié)點(diǎn))頁(yè)是5170,使用該頁(yè)來(lái)查看數(shù)據(jù)分布情況:
--===================================--查看非葉子節(jié)點(diǎn)來(lái)查看數(shù)據(jù)和頁(yè)的對(duì)應(yīng)情況DBCC PAGE('TestDB',1,5170,3)
觀察上圖的ID,我們可以發(fā)現(xiàn)以下規(guī)律
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
從上面的數(shù)據(jù)不難看出,每頁(yè)數(shù)據(jù)逐漸一半一半地減少。再通過(guò)sys.fn_dblog(NULL,NULL)來(lái)查看事務(wù),最后一次插入操作引發(fā)1次插入事務(wù)和8個(gè)頁(yè)拆分事務(wù)。
由此,我們推斷出在上面的插入過(guò)程中,發(fā)生了以下操作:
1. 新事務(wù)開(kāi)始,一行新數(shù)據(jù)需要插入到數(shù)據(jù)頁(yè)中,該數(shù)據(jù)行不是數(shù)據(jù)頁(yè)最尾數(shù)據(jù)行
2. 判斷頁(yè)中剩余空間,發(fā)現(xiàn)數(shù)據(jù)頁(yè)不能存放新插入行,需要頁(yè)拆分
3. 開(kāi)啟一個(gè)新事務(wù),將頁(yè)中一半數(shù)據(jù)移動(dòng)到一個(gè)新的頁(yè)面,關(guān)閉事務(wù)
4. 循環(huán)第2步和第3步,直到有一數(shù)據(jù)頁(yè)能存放新插入的行
5. 插入數(shù)據(jù),提交事務(wù)
到此,很多人就會(huì)疑問(wèn),拆分一半到底是數(shù)據(jù)行數(shù)的一半還是數(shù)據(jù)占用空間大小的一半呢?
讓我們?cè)僮鲆粋€(gè)實(shí)驗(yàn)
--==========================================--清除表中數(shù)據(jù)TRUNCATE TABLE TB01--=======================================--插入198條數(shù)據(jù),所有數(shù)據(jù)存放在一個(gè)8KB的數(shù)據(jù)頁(yè)中--前99條數(shù)據(jù)和后99天數(shù)據(jù)的大小不相同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--====================================--插入一行數(shù)據(jù)導(dǎo)致頁(yè)拆分INSERT INTO TB01(ID,C1)SELECT 100,REPLICATE(N'1',2000)
同樣適用根節(jié)點(diǎn)來(lái)數(shù)據(jù)分布:
由于后99行數(shù)據(jù)占用的空間大小較大,在頁(yè)拆分時(shí),沒(méi)有將后99條全部拆分到新的數(shù)據(jù)頁(yè)上,因此我們得出結(jié)論,頁(yè)拆分時(shí)是按照數(shù)據(jù)占用空間大小來(lái)拆分的,與數(shù)據(jù)行數(shù)無(wú)關(guān)。
--=====================================================================================================
總結(jié):
1.發(fā)現(xiàn)在頁(yè)拆分時(shí),會(huì)按照頁(yè)中數(shù)據(jù)占用空間的情況,將占用空間一半的數(shù)據(jù)移動(dòng)到新的數(shù)據(jù)頁(yè)上
2.如果拆分后仍無(wú)法存放新數(shù)據(jù),則繼續(xù)頁(yè)拆分,知道有數(shù)據(jù)頁(yè)可以存放新數(shù)據(jù)為止,因此一次插入操作可能會(huì)引起多次頁(yè)拆分。
3.每次頁(yè)拆分會(huì)被當(dāng)成一個(gè)事務(wù)處理,頁(yè)拆分的事務(wù)單獨(dú)提交(在提交插入事務(wù)之前已提交),及時(shí)插入失敗,頁(yè)拆分的事務(wù)也不會(huì)回滾。
4.更新導(dǎo)致的頁(yè)拆分情況與插入導(dǎo)致的頁(yè)拆分類(lèi)似
PS:
1.在測(cè)試中,未發(fā)現(xiàn)沒(méi)有按照一半空間拆分的情況,但沒(méi)有找到相關(guān)官方文檔來(lái)證明。
--===========================================================================================================
小倉(cāng)優(yōu)子,各位大神應(yīng)該知道的,不用我多說(shuō)吧。吼吼
新聞熱點(diǎn)
疑難解答
圖片精選