在做性能優(yōu)化時(shí),經(jīng)常需要?jiǎng)?chuàng)建索引,維護(hù)索引,或重建,或重組;在創(chuàng)建索引時(shí),索引的數(shù)據(jù)頁(yè)有時(shí)需要填充滿,有時(shí)需要預(yù)留一定比例的空閑空間;在分析查詢的執(zhí)行計(jì)劃之后,推薦創(chuàng)建覆蓋索引(covering index),優(yōu)化查詢語(yǔ)句,使用執(zhí)行計(jì)劃通過(guò)Index Seek來(lái)獲取少量數(shù)據(jù)等,這些都是索引優(yōu)化不得不知的要點(diǎn)。
一,索引的重組(Reorganize)和重建(Rebuild)
在SQL Server中,索引(Index)是B-Tree(balance tree)結(jié)構(gòu),每個(gè)Page之間都有雙向指針鏈接在一起。Index是在table結(jié)構(gòu)之外,獨(dú)立存在的存儲(chǔ)結(jié)構(gòu)。Index能使查詢性能帶來(lái)飛躍的主要原因是:Index 結(jié)構(gòu)更小,能夠更快加載到內(nèi)存;Index ey物理順序和邏輯一致,數(shù)據(jù)的預(yù)讀取能夠提高數(shù)據(jù)的加載速度,SQL Server 每次讀取操作都會(huì)將物理物理相鄰的多個(gè)Page一起加載到內(nèi)存。
BTree結(jié)構(gòu)決定 Index 的葉子節(jié)點(diǎn),從左到右使依次增大,如圖是Index的葉子節(jié)點(diǎn),左邊的Index Key最小,右邊的Index Key最大:
如果更新數(shù)據(jù)導(dǎo)致index key變化,例如,將index key 由4變更為9,那么必須將9放置在8之后,10之前,如果8所在的Page有空間容納9,那么SQL Server只需要將9移動(dòng)到8之后,原來(lái)的4被刪除,這會(huì)降低原page中數(shù)據(jù)存儲(chǔ)的密度,造成一個(gè)碎片(fragment),即:3和5之間存在空閑空間,但是物理順序和邏輯順序還是一致的。
如果8和10所在的page不能容納9,那么 SQL Server 選擇最節(jié)省,最有效的方式:拆分Page。試想,如果不拆分page,那么,5,6,7,8 這幾個(gè)數(shù)據(jù)行都要向前移動(dòng),為9騰挪空間。在SQL Server中,數(shù)據(jù)移動(dòng)是十分浪費(fèi)IO,內(nèi)存和CPU資源的,IO必須在CPU的調(diào)控下進(jìn)行。
拆分Page是指分配一個(gè)新的Page,將8所在的Page上的數(shù)據(jù)的一半(后一半,或前一半)移動(dòng)在新的Page上,如圖,將page中的后一半移動(dòng)在新的page上,通過(guò)指針連接在一起,保持邏輯順序的一致性,但是物理順序已經(jīng)不連續(xù)了。
對(duì)于Index Key移動(dòng)之后,其物理順序和邏輯順序仍然保持一致,這會(huì)導(dǎo)致索引出現(xiàn)碎片,數(shù)據(jù)存儲(chǔ)的密度降低;而拆分page,不僅將page存儲(chǔ)數(shù)據(jù)的密度降低一半,而且數(shù)據(jù)的物理順序和邏輯順序,導(dǎo)致SQL Server的預(yù)讀取操作效果下降。針對(duì)Index的這兩種情況,根據(jù)Index的碎片率,對(duì)Index 進(jìn)行重組(Reorganize)或重建(Rebuild)。
1,索引Reorganize 和 Rebuild的過(guò)程
Rebuild 是重新創(chuàng)建,將索引占用的原有存儲(chǔ)空間釋放,重新申請(qǐng)空間來(lái)創(chuàng)建索引結(jié)構(gòu),這意味著,SQL Server存儲(chǔ)引起需要為索引結(jié)構(gòu)分配新的數(shù)據(jù)頁(yè),在重建索引結(jié)構(gòu)時(shí),索引占用的存儲(chǔ)空間是其實(shí)際大小的2倍還多。
Reorganize 是重新組織索引結(jié)構(gòu)的葉子節(jié)點(diǎn)。在重組索引時(shí),SQL Server存儲(chǔ)引擎首先按照原有的填充因子(Fi