曲演雜壇 頁拆分

2021-09-06 14:50:41 字數 3845 閱讀 9697

以下測試基於版本:sql server 2008

很多同行會問起頁拆分的相關的問題,自己對頁拆分頁迷迷糊糊,有點雲裡霧裡的感覺,今天來測試測試。

首先生成測試資料

--

****************************************=

--使用testdb資料庫來測試

usetestdb

godrop

table

tb01

go--

***********************************====

--建立測試表tb01

create

table

tb01

( id

intprimary

key,

c1 nvarchar(max))

go--

***********************************====

--插入420條資料,所有資料存放在乙個8kb的資料頁中

insert

into

tb01(id,c1)

select t.rid,n'c'

from

(select

row_number()

over(order

byobject_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)--

***********************************=

--檢視資料頁

我們可以很清楚地發現,在插入一行資料後,資料頁由原來的一頁變成了9頁(乙個非葉子節點頁和8個葉子節點頁),是不是很不科學呢? 新插入的資料只需要乙個資料頁來存放,加上原來的資料,只需要2個資料庫便可以存放,為什麼會造成這麼多頁面使用呢?

通過上面的圖,可以清楚看到資料有兩層,非葉子節點(也是根節點)頁是5170,使用該頁來檢視資料分布情況:

--

***********************************

--檢視非葉子節點來檢視資料和頁的對應情況

觀察上圖的id,我們可以發現以下規律

從上面的資料不難看出,每頁資料逐漸一半一半地減少。再通過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

byobject_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

byobject_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. 在測試中,未發現沒有按照一半空間拆分的情況,但沒有找到相關官方文件來證明。

小倉優子,各位大神應該知道的,不用我多說吧。吼吼

曲演雜壇 蛋疼的ROW NUMBER函式

使用row number來分頁幾乎是家喻戶曉的東東了,而且這東西簡單易用,簡直就是程式設計師居家必備之殺器,然而row number也不是一招吃遍天下鮮的無敵bug般存在,最近就遇到幾個小問題,拿出來供大家娛樂下。問題1 為什麼加where條件就慢,不加反而快?查詢sql with tempas s...

曲苑雜壇 收縮資料庫檔案

很多人在刪除大量資料後收縮資料庫,卻發現沒法收縮到預期效果。由於使用dbcc shrinkfile來收縮資料檔案時,是針對資料區來收縮,因此可以先使用dbcc showfilestats來檢視檔案中未使用的分割槽數 totalextents usedextents 如果刪除大量資料但未使用分割槽數比...