SQL Server 2016支持哈希查找,用戶能夠在內存優化表(Memory-Optimized Table)上建立哈希索引(Hash Index),使用Hash 查找算法,實現數據的極速查找。在使用上,Hash Index 和B-Tree索引的區別是:Hash Index 是無序查找,Index Key必須所有做爲查找的條件,多個鍵值之間是邏輯與關係,而且只能執行等值查找,而B-Tree索引是有序查找,不須要Index Key都做爲查找,只須要前序字段都存在,還能夠進行大於、小於、等於等比較操做;在存儲結構上,Hash Index使用Hash Table實現,存在Hash 衝突,而B-Tree索引的結構是B-Tree結構,存在頁拆分和索引碎片等問題。算法
在《數據結構》課程中,Hash查找的算法是:以關鍵字k爲自變量,經過一個映射函數h,計算出對應的函數值y=h(k)(y稱做哈希值,或哈希地址),根據函數值y,將關鍵字k存儲在數組(bucket數組)所指向的鏈表中。在進行哈希查找時,根據關鍵字,使用相同的函數h計算哈希地址h(k),而後直接尋址相應的Hash bucket,直接到對應的鏈表中取出數據。所以,Hash 查找算法的數據結構由Hash Bucket數組,映射函數f和數據鏈表組成,一般將Bucket數組和數據鏈表稱做Hash Table,如圖,Hash Table由5個buckets和7個數據結點組成:sql
哈希查找的時間複雜度是O(n/m),n是指數據結點的數量,m是bucket的數量,在理想狀況下,Hash Bucket足夠多,Hash函數不產生重複的Hash Value,哈希查找的時間複雜度最優到達O(1),可是,在實際應用中,哈希函數有必定的概率出現重複的哈希地址,產生哈希衝突,時間複雜度會低於O(n/m);在最差的狀況下,時間複雜度是O(n)。數組
Hash Index使用Hash查找算法實現,SQL Server內置Hash函數,用於全部的Hash Index,所以,Hash Index就是Hash Table,由Hash Buckets數組和數據行鏈表組成。建立Hash Index時,經過Hash函數計算Index Key的Hash地址,Hash地址不一樣的數據行指向不一樣的Bucket,Hash地址相同的數據行指向相同的Bucket,若是多個數據行的Hash地址相同,都指向同一個Bucket,那麼將這些數據行連接在一塊兒,組成一個鏈表。數據結構
A hash index consists of an array of pointers, and each element of the array is called a hash bucket. The index key column in each row has a hash function applied to it, and the result of the function determines which bucket is used for that row. All key values that hash to the same value (have the same result from the hash function) are accessed from the same pointer in the hash index and are linked together in a chain. When a row is added to the table, the hash function is applied to the index key value in the row. If there is duplication of key values, the duplicates will always generate the same function result and thus will always be in the same chain.app
舉例說明,假定哈希函數是h(k)=Length(k),用於計算Index Key的字符個數,在內存優化表(Name,City)上建立Hash Index,Index ptr指向鏈表中的下一個數據行,若是沒有下一個數據行,那麼該指針爲NULL:ide
1,以Name爲Index Key建立Hash Index函數
第一個數據行的Name是「Jane」,HashValue是4,將該行數據映射到下標爲4的Bucket中(Bucket數組的第五個元素),因爲該數據行是第一個數據結點,Index ptr爲NULL。性能
第二個數據行,Name值是「Greg」,HashValue是4,映射到下標爲4的Bucket中,和第一個數據行連接在一塊兒,組成一個鏈表(Chain),插入數據結點時,使用頭部插入法,新的數據節點做爲頭結點,將頭節點的Index ptr(next pointer)指針指向數據鏈表的第一個數據結點,如圖,新的頭結點「Greg」的Index ptr指向第一個數據行「Jane」。優化
2,建立第二個Hash Index,以City爲Index Keyui
當建立第二個Hash Index時,每一個數據行結構中包含兩個Index ptr指針,都用於指向下一個數據節點(Next Pointer):第一個Index ptr用於Index Key爲Name的Hash Index,當出現相同的Hash Value時,該指針指向鏈表中下一個數據行,使數據行連接到一塊兒組成鏈表;第二個Index ptr用於Index Key爲City的Hash Index,指向鏈表中下一個數據行。
所以,當建立一個新的Hash Index時,在數據結構上,SQL Server須要建立Hash Buckets數組,並在每一個數據行中增長一個Index ptr字段,根據Index Key爲Index ptr賦值,組成一個新數據行鏈表,可是數據行的數量保持不變。
3,Hash 函數
在建立Hash Index時,不須要編寫Hash 函數,SQL Server內置Hash函數:
泊松分佈不是均勻分佈,Index Key不是均勻地分佈在Hash bucket數組中。例如,有n個Hash Bucket,n個不一樣的Index Key,泊松分佈產生的結果是:大約有1/3的Hash Bucket是空的,大約1/3的Hash bucket存儲一個Index Key,剩下1/3的Hash Buckets存儲2個Index Key。
4,Hash Index的鏈表長度
不一樣的Index Key,通過hash函數映射以後,可能生成相同的Hash Value,映射到相同的bucket中,產生 Hash 衝突。Hash算法,將映射到相同Bucket的多個Index Key組成一個鏈表,鏈表越長,Hash Index查找性能越差。
在DMV:sys.dm_db_xtp_hash_index_stats (Transact-SQL)中,表示Hash Index鏈長的字段有:avg_chain_length 和 max_chain_length ,鏈長應保持在2左右;鏈長過大,代表太多的數據行被映射到相同的Bucket中,這會顯著影響Hash Index的查詢性能,致使鏈長過大的緣由是:
在內存優化表上建立Index,不能使用Create Index命令,SQL Server 2016支持兩種方式建立索引:
1,在建立內存優化表時建立Hash Index
建立Hash Index的語法是:
INDEX index_name [ NONCLUSTERED ] HASH WITH (BUCKET_COUNT = bucket_count)
建立Hash Index的示例:
--create memory optimized table create table [dbo].[products] ( [ProductID] [bigint] not null, [Name] [varchar](64) not null, [Price] decimal(10,2) not null, [Unit] varchar(16) not null, [Description] [varchar](max) null, constraint [PK__Products_ProductID] primary key nonclustered hash ([ProductID])with (bucket_count=2000000) ,index idx_Products_Price nonclustered([Price] desc) ,index idx_Products_Unit nonclustered hash(Unit) with(bucket_count=40000) ) with(memory_optimized=on,durability= schema_and_data) go
2,使用Alter Table命令建立Hash Index
alter table [dbo].[products] add index hash_idx_Products_Name nonclustered hash(name)with(bucket_count=40000);
總結Hash Index的特色:
參考文檔:
Guidelines for Using Indexes on Memory-Optimized Tables
Troubleshooting Common Performance Problems with Memory-Optimized Hash Indexes