SQL Server 內存優化表的索引設計


測試的版本:SQL Server 2017

內存優化表上可以創建哈希索引(Hash Index)和內存優化非聚集(NONCLUSTERED)索引,這兩種類型的索引也是內存優化的,稱作內存優化索引,和基於硬盤的傳統索引有很大的區別:

  • 索引結構存儲在內存中,沒有索引碎片和填充因子
  • 對索引所作的更新不會寫入事務日志文件,這導致索引的更新操作性能非常高

一,創建內存優化索引

在創建內存優化表的索引時,第一種方式是在創建表時定義索引,第二種方式是先創建內存優化表,然后通過alter table命令修改表結構,向表中添加索引,而表級別的索引語法如下所示:

<table_index> ::=
  INDEX index_name
{   [ NONCLUSTERED ] HASH (column [ ,... n ] ) WITH (BUCKET_COUNT = bucket_count)
  | [ NONCLUSTERED ] (column [ ASC | DESC ] [ ,... n ] ) [ ON filegroup_name | default ]
}

舉個例子,修改表結構,向表中添加哈希索引,在定義索引時必須設置bucket_count的數量:

ALTER TABLE table_name
    ADD INDEX idx_hash_index_name  HASH (index_key) WITH (BUCKET_COUNT = 64);  

二,內存優化索引的性能優化

內存優化索引適用的場景是:

  • 非聚集索引   如果查詢中包含order by子句、或者包含 where index_column > value等范圍掃描操作 ,推薦使用非聚集索引。
  • 哈希索引       如果查詢中包含點查找(point lookup),例如 where index_column = value,而不是范圍掃描,推薦使用哈希索引。

1,哈希索引性能優化

哈希索引是指SQL Server引擎應用哈希函數F(x),把索引鍵值(Index Key)轉換為哈希表(哈希索引)。當哈希值相同,而索引鍵不同時,稱作產生一個哈希沖突。把哈希值相同的索引鍵鏈接在一起,組成一個鏈式結構(chain),也稱作沖突鏈。在查找時,需要遍歷沖突鏈來查找數據,因此,沖突鏈變長,會降低哈希查找的性能。

哈希沖突是不可避免的,以下兩種情況,會產生較多的哈希沖突:

  • 如果索引鍵存在大量的重復值,
  • 當hashbucket的數量較少時

這兩種情況導致哈希沖突鏈變長,降低哈希查找的性能,用戶可以通過降低索引鍵的重復值、增加hashbucket的數量來減少哈希沖突。

哈希索引只能點查找(point lookup),並且要求在where子句中應用index key的所有字段、等值條件和與邏輯,例如,哈希索引鍵是colA和colB,在where子句中必須滿足:同時出現所有索引鍵、等值條件和與邏輯,也就是:where colA= value1 and colB=value2,只有這樣,才能使用哈希索引進行點查找,否則無法應用哈希索引。

2,內存優化非聚集索引的優化

內存優化非聚集索引的結構是Bw-Tree,在結構上類似於B-Tree結構,具有樹形結構、鍵值是有序的等特點。

從性能上來看,Bw-Tree索引有三個主要特點:

  • 通過無鎖(Lock-Free)的方式來操作Bw-Tree樹,提升了隨機讀和范圍讀的性能。
    • 索引按照前序字段進行排序,在查找時,索引鍵的前序字段非常重要,前序字段必須出現在where/on 子句的條件斷言中。
    • 適合范圍查找,只適用於按照索引定義的排序方向的查找,而不能用於逆向排序的查找
  • 通過Log-Structed Storage方式寫數據,傳統的checkpoint寫數據的方式是隨機寫,而Log-Structed Storage是順序寫,提高寫操作的性能。
  • 對數據的更新采用Delta Update方式,提高了緩存的命中率。

Bw-Tree結構的索引,和普通的B-Tree結構相比,讀寫性能提高,解決了高性能讀和寫不能兼得的問題。

三,內存優化的非聚集索引的結構特點

內存非聚集索引類似於B-Tree結構,稱作Bw-Tree。從整體上看,Bw-Tree是按照Page ID組織的頁面映射。

在Bw-Tree結構中,每個索引Page具有一組有序鍵值(該結構類似於普通的B樹),鍵值是按照大小順序排列的,並且索引中包含層次結構,父級別指向子級別,葉級別指向數據行。

差異是Bw-Tree可以把多個數據行連接在一起,索引結構中的頁面指針是邏輯頁面的ID,這個邏輯頁面的ID實際上是頁面映射表的偏移量,該映射表具有每個頁面的物理地址,通過偏移量找到每個頁面在內存中實際的物理地址。

在非葉子級別中,父級別的頁面中存儲的鍵值是它指向的子級頁面中的鍵值的最大值,並且每一行還包含該頁面邏輯頁ID(偏移量)。葉級數據頁不僅包含鍵值,還包含頁面的物理地址。

Bw-Tree結構大致如下圖所示:有類似B-Tree的樹形結構(存儲的數據和索引)和Mapping Table(存儲邏輯頁面ID和物理地址的映射)。

在內存非聚集索引中,沒有索引頁的就地更新(in-place update),為了實現該目的,引入了新的更新機制:

  • 在更新頁時,不需要latch 和lock
  • 索引頁不是固定的大小

Bw-Tree結構解決了B-tree高性能讀和寫不能兼得的問題,可能會存在性能抖動。

四,哈希索引的結構特點

哈希索引包含一個由指針構成的數組,數組中的每個元組叫做一個hash bucket:

  • 每個hash bucket占用8Bytes,用於指向key entry構成的鏈式列表
  • 每個entry主要由索引鍵的值、對應的數據行的地址和指向下一個entry的指針構成
  • 每個entry有一個指針,用於指向鏈中下一個entry,通過這種方式,entry構成鏈式結構

哈希索引的結構,如下圖所示,左側是哈希表,右側上一是表數據(Name、City)+時間戳+索引指針,右側中下的兩行是表數據,中間通過Index prt鏈接為一個chain。

hash bucket的數量必須在索引定義時指定:

  • 哈希索引的hash bucket的最大數量是 1,073,741,824
  • 較短的鏈式列表比較長的鏈式列表性能更好
  • hash bucket的數量與表中唯一值的數量的比值越低,每個hash bucket指向的鏈式列表的長度越長,性能越差。因此,應該適當增加hash bucket的數量。
  • 理想情況下,hash bucket最好是表中唯一值數量的1到2倍。

 

參考文檔:

Index Architecture & Design

關於Bw-Tree結構的兩個Paper


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM