1. 程式人生 > >SQL Server 記憶體優化表的索引設計

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結構的兩個P