以下測試基於版本:sql server 2008
很多同行會問起頁拆分的相關的問題,自己對頁拆分頁迷迷糊糊,有點雲裡霧裡的感覺,今天來測試測試。
首先生成測試資料
--現在表tb01上有乙個資料頁(接近填滿),使用dbcc檢視****************************************=
--使用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--
***********************************=
然後嘗試插入資料導致頁拆分:
--***********************************=
--插入一行資料
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 如果刪除大量資料但未使用分割槽數比...