前言: 本文對這篇博客Clustered Tables vs Heap Tables 的翻譯, 如有翻譯不對或不好的地方,敬請指出,大家一起學習進步。
問題描述
創建一個新表時,一個非常重要的設計原則就是創建還是不創建聚集索引的決定。沒有聚集索引的表被稱為堆,擁有聚集索引的表叫聚集索引表。 聚集索引表比堆表擁有一些好處(優勢),比如聚集索引表是基于聚集索引鍵順序存儲的,正因為如此,所以通過聚集索引可以快速查找某一行;可以通過重建聚集索引重新組織數據。當你對表進行INSERT、UPDATE、DELETE等操作時可能會使物理數據變得碎片化,這種碎片化可能會導致你浪費大量數據庫存儲空間,因為本來可以存儲在一頁的數據,需要存儲在多個數據頁上(Pages),那么,我們該怎么做呢?
解決方案
我們要解決的首要問題是發生在數據庫正常活動中的碎片。你的表是否擁有聚集索引 將決定您是否可以在數據庫物理層面很容易的解決碎片化問題。因為堆或聚集索引決定你表數據的物理存儲,每個表要么擁有一個聚集索引或沒有一個聚集索引,所以每個表要么是一個堆或聚集索引表。
讓我們來看看一個堆表和聚集索引表之間的差異:
HEAP
數據存儲沒有任何特定的順序。
不能快速的找到特定數據,除非也有非聚集索引。
數據頁之間沒有指針關聯,所以順序訪問需要重新返回到索引分配映射(IAM)頁
既然沒有聚集索引,所以不用額外的時間去維護聚集索引。
既然沒有聚集索引,所以不用額外的空間去存儲聚集索引樹。
堆表的索引在sys.indexes目錄視圖的記錄的index_id字段值為0
Clustered Table
數據存儲基于聚集索引鍵順序存儲。
如果查詢時使用聚集索引列,數據可以基于聚集索引鍵快速檢索到。
數據頁之間有指針鏈接,可以更快速的順序訪問。
當INSERT、UPDATE、DELETE操作時,需要額外的時間維護聚集索引。
需要額外的空間存儲聚集索引樹。
聚集索引表在sys.indexes目錄視圖的記錄的index_id值為1.
所以,基于以上你可以看到有一個表是否具有聚簇索引將決定表的一些根本性的不同之處。
碎片化問題
所有的表都會發生的一個問題就是碎片化的問題。根據不同的操作,比如刪除,插入和更新,您的堆表和聚集索引表將會變得越來越碎片化。碎片化很多時候取決于INSERT、UPDATE、DELTE這類操作,以及用作聚集索引的鍵。
如果您的堆表只有INSERT操作,你的表不會變得碎片化,因為只有新的數據寫入。
如果您的聚集索引鍵是連續的,比如一個自增字段。并且對該表你只有INSERT操作,這同樣也不會變得碎片化,因為新的數據總是寫在聚簇索引的后面。
但是,如果你的表是一個堆或聚集表,并有大量的插入,更新和刪除操作,數據頁碎片化可能會變得越來越嚴重。這不僅會導致浪費額外的空間,而且需要讀取額外的數據頁來滿足查詢。
當一個表在堆上創建,SQL Server不會強迫在那個新數據頁(New Page)寫入數據。每當新的數據寫入時,該數據總是寫在表的末端,或者分配給該表中的下一個可用的頁面上。當數據被刪除時,數據頁上的空間釋放出來,但它不重復使用,因為新數據總是寫入到下一個可用的頁面。
具有聚簇索引,根據索引鍵,新的記錄可能會被寫入到現有的頁面,這些頁面可能存在的空閑的空間或者有可能需要分割成多個頁面的頁面。以便插入新的數據。刪除時會發生同樣的問題時,與一個堆對比,但是這些空閑間可以再次使用,如果數據需要插入到具有可用空間的現有頁面中的一個。
所以,基于以上敘述 ,你的堆表可能變得比你的聚集表更加支離破碎。
查看碎片化要確定您的聚集索引表或堆表是否碎片化,你要么通過運行DBCC SHOWCONTIG(SQL SEREVER 2000或SQL SEREVER 2005)查看,或使用新的DMVsys.dm_db_index_physical_stats(SQL SERVER 2005 以及以后版本)。這些命令能讓你查看表中可能存在的碎片化問題。如需更多相關信息,看看以前的這篇文章提示:SQL Server 2000 to 2005 Crosswalk - Index Rebuilds.
解決碎片化
聚集索引表
解決聚集索引的碎片化可以很容易地通過重建或重新組織你的聚集索引來完成。這表現在這之前的提示: SQL Server 2000 to 2005 Crosswalk - Index Rebuilds
堆表
對于堆表來說,這個不太容易的。您可以采取以下不同的方法來解決碎片問題:
附加信息
當你通過企業管理器或Management Studio創建一個新表并在新表中指定一個主鍵,管理工具會自動為其創建一個聚集索引,但可以被重寫。當通過腳本創建一個新表時,你需要明確指定創建聚集索引。所以,正是由于主鍵關系,你大部分的表將會擁有一個聚集索引,但如果創建表時,你不指定一個主鍵或建立聚集索引,該表的數據將被存儲為一個堆。
下一步
維持表和索引的碎片化在控制范圍內是保持數據庫最佳性能的一個關鍵過程?,F在你可以明白一個堆與聚集索引表在解決碎片化上的不同,看看你的表結構,看看你需要解決這些問題。
即使對所有表一個星期做一次索引重建,你的堆表是永遠不會解決瑣碎化問題的,所以你需要想出另一種策略來處理堆表的碎片問題。
一起來看看這些相關技巧:
SQL Server 2000 to 2005 Crosswalk - Database Fragmentation.
SQL Server 2000 to 2005 Crosswalk - Index Rebuilds.
基于上述論證,似乎所有的表都應該有一個聚集索引。在大多數情況下是這樣,但也可能由于某種原因,你不希望有一個聚集索引。一個原因可能是該表只有INSERT操作,例如一個日志記錄的表。但是毫無疑問,有聚集索引一定好過沒有聚集索引
新聞熱點
疑難解答