本主題將著重於針對哈希索引的常見問題進行疑難解答和解決。
搜尋需要哈希索引鍵數據行的子集
問題: 哈希索引需要所有索引鍵數據行的值,才能計算哈希值,並在哈希表中找出對應的數據列。 因此,如果查詢只包含 WHERE 子句中索引鍵子集的相等述詞,SQL Server 就無法使用索引搜尋來找出 WHERE 子句中對應述詞的數據列。
相反地,已排序的索引,例如磁碟型非叢集索引和記憶體優化的非叢集索引,只要索引鍵欄位是索引中的前置欄位,就支援在索引鍵欄位子集上進行索引查詢。
癥狀: 這會導致效能降低,因為 SQL Server 需要執行完整數據表掃描,而不是索引搜尋,這通常是較快的作業。
如何進行疑難排解: 除了效能降低之外,檢查查詢計劃時會顯示使用掃描而非索引搜尋。 如果查詢相當簡單,則查詢文字和索引定義的檢查也會顯示搜尋是否需要索引鍵數據行的子集。
請考慮下表和查詢:
CREATE TABLE [dbo].[od]
(
o_id INT NOT NULL,
od_id INT NOT NULL,
p_id INT NOT NULL,
CONSTRAINT PK_od PRIMARY KEY NONCLUSTERED HASH (o_id, od_id) WITH (BUCKET_COUNT = 10000)
)
WITH (MEMORY_OPTIMIZED = ON)
SELECT p_id
FROM dbo.od
WHERE o_id=1
數據表在兩個數據行上有哈希索引(o_id,od_id),而查詢在 (o_id) 上具有相等述詞。 由於查詢僅對索引鍵欄位的子集具有相等述詞,SQL Server 無法使用 PK_od 進行索引搜尋操作,反而必須執行完整索引掃描。
因應措施: 有許多可能的因應措施。 例如:
將索引重新建立為非叢集類型,而不是非叢集哈希。 記憶體優化的非叢集索引是有排序的,因此 SQL Server 可以在索引鍵的前導數據行上執行索引查找。 範例產生的主鍵定義會是
constraint PK_od primary key nonclustered。將目前的索引鍵變更為符合 WHERE 子句中的欄位。
新增與查詢 WHERE 子句中的數據行相符的新哈希索引。 在這裡範例中,產生的數據表定義將如下所示:
CREATE TABLE dbo.od ( o_id INT NOT NULL, od_id INT NOT NULL, p_id INT NOT NULL, CONSTRAINT PK_od PRIMARY KEY NONCLUSTERED HASH (o_id,od_id) WITH (BUCKET_COUNT=10000), INDEX ix_o_id NONCLUSTERED HASH (o_id) WITH (BUCKET_COUNT=10000) ) WITH (MEMORY_OPTIMIZED=ON)
請注意,如果給定索引鍵值有許多重複的數據列,記憶體優化哈希索引不會以最佳方式執行:在此範例中,如果數據行的唯一 o_id值數目遠小於數據表中的數據列數目,則加入索引不是最佳方式(o_id):相反地,將索引的類型 PK_od從哈希變更為非叢集,會是更好的解決方案。 如需詳細資訊,請參閱 確定哈希索引的正確桶數。