(SQL Server) Index Fragmentation 產生原因,該如何做對應的調整?!

Jerry Wu
8 min readJun 22, 2021

--

前言

當資料庫中的索引碎裂(Index Fragmentation)程度過高時,索引的效率就會大大降低,這將嚴重的影響查詢效能,然而索引碎裂的產生原因是甚麼呢?為了避免索引碎裂發生,我們該如何做對應的調整?以下將分為三個段落說明:

1. Index Fragmentation 產生原因

2. 該如何做對應的調整

3. 實際操作

1. Index Fragmentation 產生原因

📒前情提要:SQL Server儲存資料的單位為Page(頁面),當建立Index(索引)時,SQL Server預設會在Page填滿資料(FillFactor為0或100),此時如果新增資料時,因為Page已經額滿,所以Index必須使用另一個Page來儲存資料,然而在一連串的異動資料過後,會導致資料散佈在各個Page上,當SQL Server想要讀取Index時,因為資料散佈在Page而使效能低落。
  • 在資料庫中,當Index存放資料的Page已經額滿時,若再新增資料就會產生一個新的Page存放資料,而導致Index的資料不連續進而降低Index效能,此時就會產生外部碎裂(External Fragmentation)的問題。
  • 在資料庫中,當資料被刪除時,Index存放到Page上的資料也會被刪除,而導致在Page中會有因刪除資料而產生的空間,這些空間會造成Index的資料不連續,此時就會產生內部碎裂(Internal Fragmentation)的問題。
  • 看了以上兩個例子可以得知,不論是對資料庫Insert還是Update都有機會產生Index Fragmentation,而一致的原因為 → Index的資料不連續

2. 該如何做對應的調整?

為了避免索引碎裂發生,我們就必須定時替資料庫健檢,也就是進行索引重組(reorganize)或索引重建(rebuild)

那麼該如何觀察資料庫中索引的碎裂狀態呢?

你可以透過 SELECT 指令搭配 sys.dm_db_index_physical_stats 這個動態管理函示,將可以查出資料庫中所有索引的碎裂狀態,T-SQL 語法如下:

有了以上的T-SQL 語法可以得到索引碎裂的狀態數據,那麼下一步就是什麼時候適合索引重組、什麼時候適合索引重建呢?

在Microsoft的官方文件中並沒有找到針對重組、重建使用時機相關資訊:

以下的判斷時機參考了不少篇相關資訊並整理在下方:

📒 索引重組的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值介於 10 到 15 之間
檢查 Internal fragmentation 部分
-當 avg_page_space_used_in_percent 的值介於 60 到 75 之間
📌 索引重建的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值大於 15
檢查 Internal fragmentation 部分
-當 avg_page_space_used_in_percent 的值小於 60
參考資訊:https://blog.miniasp.com/post/2009/01/18/Let-SQL-Server-Tell-You-Which-Indexes-to-Rebuild-or-Reorganize
📒 索引重組的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值介於 10 到 30之間
📌 索引重建的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值大於 30
參考資訊:https://solutioncenter.apexsql.com/why-when-and-how-to-rebuild-and-reorganize-sql-server-indexes/
📒 索引重組的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值介於 5 到 30之間
📌 索引重建的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值大於 30
參考資訊:https://www.mssqltips.com/sqlservertip/4470/script-to-manage-sql-server-rebuilds-and-reorganize-for-index-fragmentation/

在找判斷時機的過程中發現其共通點皆是有範圍的做索引重組(reorganize)或索引重建(rebuild),而非全部Index皆執行,可以想像的是,若將全部Index皆做此操作通常會導致資源上的浪費[時間/空間]。

在第二小節我們可以得知為了避免索引碎裂發生,我們就必須定時替資料庫進行索引重組(reorganize)或索引重建(rebuild),然而並非全部Index皆執行,而是有範圍的做索引重組(reorganize)或索引重建(rebuild)。

3. 實際操作

1. 建立一張表 [USERS],欄位[ID]為其Index

2. Insert 100000筆資料刻意產生 Index Fragmentation

3. 使用T-SQL語法自動產出此Index適合索引重組(reorganize)或索引重建(rebuild),此處的參數如下:

📒 索引重組的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值介於 5 到 30之間
📌 索引重建的時機
檢查 External fragmentation 部分
-當 avg_fragmentation_in_percent 的值大於 30

4. 複製自動產出的T-SQL語法 (ALTER INDEX…),並執行

5. 將可以明顯看出[AvgFragmentationPercentage]從 97.94 降為 0

以上就是這次Index Fragmentation的內容啦,聊了產生原因,可以如何做對應的調整,最後Demo一次重建Index,若有問題or錯誤歡迎留言討論!

謝謝你的閱讀!如果有任何回饋或疑問,歡迎留言給我!
如果對我的文章有興趣,請不吝按下Follow & Clap!
每個月都會認真更新文章唷😊 千萬別錯過了~

--

--

Jerry Wu
Jerry Wu

Written by Jerry Wu

Full-Stack Engineer,熱愛接觸Web前後端、DevOps相關技術與知識,喜歡分享、旅遊和桌球🏓