索引碎片與填充因子

在SQL Server中,存儲數據的最小單位是頁,每一頁所能容納的數據爲8060字節.而頁的組織方式是經過B樹結構(表上沒有彙集索引則爲堆結構,不在本文討論之列)以下圖:
http://images.cnblogs.com/cnblogs_com/CareySon/201201/201201060845425012.png
在彙集索引B樹中,只有葉子節點實際存儲數據,而其餘根節點和中間節點僅僅用於存放查找葉子節點的數據.
每個葉子節點爲一頁,每頁是不可分割的. 而SQL Server向每一個頁內存儲數據的最小單位是表的行(Row).當葉子節點中新插入的行或更新的行使得葉子節點沒法容納當前更新或者插入的行時,分頁就產生了.在分頁的過程當中,就會產生碎片.數據庫

理解外部碎片性能

首先,理解外部碎片的這個「外」是相對頁面來講的。外部碎片指的是因爲分頁而產生的碎片.好比,我想在現有的彙集索引中插入一行,這行正好致使現有的頁空間沒法知足容納新的行。從而致使了分頁:學習


由於在SQL SERVER中,新的頁是隨着數據的增加不斷產生的,而彙集索引要求行之間連續,因此不少狀況下分頁後和原來的頁在磁盤上並不連續.
這就是所謂的外部碎片.
因爲分頁會致使數據在頁之間的移動,因此若是插入更新等操做常常須要致使分頁,則會大大提高IO消耗,形成性能降低.
而對於查找來講,在有特定搜索條件,好比where子句有很細的限制或者返回無序結果集時,外部碎片並不會對性能產生影響。但若是要返回掃描彙集索引而查找連續頁面時,外部碎片就會產生性能上的影響.
在SQL Server中,比頁更大的單位是區(Extent).一個區能夠容納8個頁.區做爲磁盤分配的物理單元.因此當頁分割若是跨區後,須要屢次切區。須要更多的掃描.由於讀取連續數據時會不能預讀,從而形成額外的物理讀,增長磁盤IO.測試

理解內部碎片
和外部碎片同樣,內部碎片的」內」也是相對頁來講的.下面咱們來看一個例子:
spa

咱們建立一個表,這個表每一個行由int(4字節),char(999字節)和varchar(0字節組成),因此每行爲1003個字節,則8行佔用空間1003*8=8024字節加上一些內部開銷,能夠容納在一個頁面中:3d

    

    當咱們隨意更新某行中的col3字段後,形成頁內沒法容納下新的數據,從而形成分頁:blog

    

   分頁後的示意圖:索引

   

    而當分頁時若是新的頁和當前頁物理上不連續,則還會形成外部碎片
 內存

內部碎片和外部碎片對於查詢性能的影響

    外部碎片對於性能的影響上面說過,主要是在於須要進行更多的跨區掃描,從而形成更多的IO操做.開發

    而內部碎片會形成數據行分佈在更多的頁中,從而加劇了掃描的頁樹,也會下降查詢性能.

    下面經過一個例子看一下,咱們人爲的爲剛纔那個表插入一些數據形成內部碎片:

    

    經過查看碎片,咱們發現這時碎片已經達到了一個比較高的程度:

    

    經過查看對碎片整理以前和以後的IO,咱們能夠看出,IO大大降低了:

    

 

對於碎片的解決辦法

    基本上全部解決辦法都是基於對索引的重建和整理,只是方式不一樣

    1.刪除索引並重建

       這種方式並很差.在刪除索引期間,索引不可用.會致使阻塞發生。而對於刪除彙集索引,則會致使對應的非彙集索引重建兩次(刪除時重建,創建時再重建).雖然這種方法並很差,可是對於索引的整理最爲有效

    2.使用DROP_EXISTING語句重建索引

       爲了不重建兩次索引,使用DROP_EXISTING語句重建索引,由於這個語句是原子性的,不會致使非彙集索引重建兩次,但一樣的,這種方式也會形成阻塞

    3.如前面文章所示,使用ALTER INDEX REBUILD語句重建索引

       使用這個語句一樣也是重建索引,可是經過動態重建索引而不須要卸載並重建索引.是優於前兩種方法的,但依舊會形成阻塞。能夠經過ONLINE關鍵字減小鎖,但會形成重建時間加長.

    4.使用ALTER INDEX REORGANIZE

       這種方式不會重建索引,也不會生成新的頁,僅僅是整理,當遇到加鎖的頁時跳過,因此不會形成阻塞。但同時,整理效果會差於前三種.

 

理解填充因子

      重建索引當然能夠解決碎片的問題.可是重建索引的代價不只僅是麻煩,還會形成阻塞。影響使用.而對於數據比較少的狀況下,重建索引代價並不大。而當索引自己超過百兆的時候。重建索引的時間將會很讓人蛋疼.

      填充因子的做用正是如此。對於默認值來講,填充因子爲0(0和100表示的是一個概念),則表示頁面能夠100%使用。因此會遇到前面update或insert時,空間不足致使分頁.經過設置填充因子,能夠設置頁面的使用程度:

     

      下面來看一個例子:

      仍是上面那個表.我插入31條數據,則佔4頁:

      

     經過設置填充因子,頁被設置到了5頁上:

     

     這時我再插入一頁,不會形成分頁:

     

     上面的概念能夠以下圖來解釋:

     

      能夠看出,使用填充因子會減小更新或者插入時的分頁次數,但因爲須要更多的頁,則會對應的損失查找性能.

     

如何設置填充因子的值

    如何設置填充因子的值並無一個公式或者理念能夠準確的設置。使用填充因子雖然能夠減小更新或者插入時的分頁,但同時由於須要更多的頁,因此下降了查詢的性能和佔用更多的磁盤空間.如何設置這個值進行trade-off須要根據具體的狀況來看.

    具體狀況要根據對於表的讀寫比例來看,我這裏給出我認爲比較合適的值:

    1.當讀寫比例大於100:1時,不要設置填充因子,100%填充

    2.當寫的次數大於讀的次數時,設置50%-70%填充

    3.當讀寫比例位於二者之間時80%-90%填充

    上面的數據僅僅是個人見解,具體設置的數據還要根據具體狀況進行測試才能找到最優.

 

總結

     本文講述了SQL SERVER中碎片產生的原理,內部碎片和外部碎片的概念。以及解決碎片的辦法和填充因子.在數據庫中,每每每個對於某一方面性能增長的功能也會伴隨着另外一方面性能的減弱。系統的學習數據庫知識,從而根據具體狀況進行權衡,是dba和開發人員的必修課.

相關文章
相關標籤/搜索