Sql-Server
在父/子關係中的子表上的聚集索引是最佳索引嗎?
聚集索引將根據索引中欄位的順序對錶中的行數據進行排序。如果是這樣,您為什麼(或不想)要在父/子關係中的子表上創建聚集索引?
讓我們假設一個經典的 order-with-orderlines 範例,在該範例中,您永遠不會在不先處理相關訂單的情況下獲取訂單。我認為在 orderid 和 orderlineid 列上都有一個聚集索引(因為聚集索引必須是唯一的)強制單個訂單的所有訂單線在物理上彼此相鄰,這將使讀取非常高效。它是否正確?如果是這樣,這種方法有缺點嗎?
您關於鄰接的假設是正確的。
如果我們以 TPC-H 為例:在
LINEITEMS
on 上對錶進行分群ORDERID
將在磁碟上定位屬於同一LINEITEM
物理相鄰的所有訂單行。這加快了獲取給定的所有訂單行的查詢ORDERID
。對父級的外鍵進行分群還允許子級和父級之間的快速合併連接。分群方法有一些缺點:
- 整個表必須在磁碟上保持排序。如果您期望大量插入而
ORDERID
不是按順序生成,則頁面拆分將更加昂貴。這是你可以扔硬體的東西。- 如果
ORDERID
按順序生成,您將在表的末尾創建一個熱點。在某些數據庫引擎(例如 SQL Server)中,這是高速插入時的問題。在 SQL Server 中,這通常會以大約 5K-10K 插入/秒的速度啟動。- 集群索引鍵要麼必須是唯一的(例如:
ORDERID
,LINENUMBER
),要麼用一些隱藏列填充以使其唯一。由於復合集群鍵必須存在於所有其他索引中,這使得二級非集群索引更大。- 當您想通過二級索引定位數據時,將表聚集儲存將強制執行 B 樹遍歷(除非二級索引覆蓋查詢)。如果您將表保留為堆,則所有其他索引將只有 8B 成本,並且您的 B 樹遍歷將減半。
在絕大多數情況下,您會希望將父級和子級都聚集在同一個前導鍵上。但是,如果您希望通過許多不同的索引訪問子表 - 可能值得考慮替代方案。