今天我使用2048的桶數的哈希索引,往Hakaton里插入100萬的記錄,測試下在哈希桶數里,哈希沖突(Hash Collision)是如何影響Hekaton的工作量——結果非常非常有意思。首先我想介紹下什么是哈希沖突。
你可能知道(非常希望),在SQL Server 2014里,Hakaton表是以哈希索引(Hash Indexes)實現的。維基百科對此有詳細介紹,這是哈希索引的應用基礎。哈希函數將索引鍵映射到哈希索引中對應的 Bucket,哈希函數的結果決定你的行最終放入那個哈希桶。如果多個鍵值哈希到同個值,SQL Server會在那個哈希桶里插入,在那個哈希桶有多個入口鏈接在一起。來看下面的圖示(來自維基百科):
從圖中可以看到,鍵值“John Smith“和“Sandra Dee”哈希到同個桶——這里是152號桶。這意味著那2行都存在同個哈希桶里,這會影響INSERT性能,還有SELECT的查詢性能。在INSERT期間,SQL Server需要維護鏈接列表,在SELECT查詢期間,SQL Server需要掃描鏈接列表。
介紹完哈希沖突后,我們來用一個簡單的例子演示下哈希沖突對性能的影響。我們來創建帶Hekaton表的數據庫:
1 -- Create new database 2 CREATE DATABASE HashCollisions 3 GO 4 5 --Add MEMORY_OPTIMIZED_DATA filegroup to the database. 6 ALTER DATABASE HashCollisions 7 ADD FILEGROUP HekatonFileGroup CONTAINS MEMORY_OPTIMIZED_DATA 8 GO 9 10 USE HashCollisions11 GO12 13 -- Add a new file to the PRevious created file group14 ALTER DATABASE HashCollisions ADD FILE15 (16 NAME = N'HekatonContainer', 17 FILENAME = N'C:/Program Files/Microsoft SQL Server/MSSQL12.MSSQLSERVER/MSSQL/DATA/HashCollisionsContainer'18 )19 TO FILEGROUP [HekatonFileGroup]20 GO21 22 -- Create a simple table23 CREATE TABLE TestTable24 (25 Col1 INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 1024),26 Col2 INT NOT NULL,27 Col3 INT NOT NULL28 )29 WITH30 (31 MEMORY_OPTIMIZED = ON, 32 DURABILITY = SCHEMA_ONLY33 )34 GO
從代碼里可以看到,這里我用的1024的哈希桶數——桶數并不多,然后我會往表里插入1000000的記錄。接下來我會創建本機編譯的存儲過程,這樣的話我可以用Hekaton的賊快速度:
1 -- Create a native compiled Stored Procedure 2 CREATE PROCEDURE InsertTestData 3 WITH 4 NATIVE_COMPILATION, 5 SCHEMABINDING, 6 EXECUTE AS OWNER 7 AS 8 BEGIN 9 ATOMIC WITH 10 (11 TRANSACTION 12 ISOLATION LEVEL = SNAPSHOT,13 LANGUAGE = N'us_english'14 )15 16 DECLARE @i INT = 017 18 WHILE @i < 100000019 BEGIN20 INSERT INTO dbo.TestTable (Col1, Col2, Col3) VALUES (@i,@i, @i)21 22 SET @i += 123 END24 END25 GO
可以看到,這里我用簡單的循環來插入1000000條記錄。在4核CPU,4G內存的虛擬機上,我們打開時間統計,來執行這個存儲過程:
1 SET STATISTICS TIME ON2 3 EXEC dbo.InsertTestData
執行時間差不多有42秒,這已經很慢了。我們不斷翻倍桶數到1048576,你會看到隨著桶數的增加,性能也得到了不斷的提升。
1 DROP PROCEDURE dbo.InsertTestData 2 DROP TABLE dbo.TestTable 3 4 -- Create a simple table 5 CREATE TABLE TestTable 6 ( 7 Col1 INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 1048576), 8 Col2 INT NOT NULL, 9 Col3 INT NOT NULL10 )11 WITH12 (13 MEMORY_OPTIMIZED = ON, 14 DURABILITY = SCHEMA_ONLY15 )16 GO17 18 19 -- Create a native compiled Stored Procedure20 CREATE PROCEDURE InsertTestData21 WITH 22 NATIVE_COMPILATION, 23 SCHEMABINDING, 24 EXECUTE AS OWNER25 AS 26 BEGIN27 ATOMIC WITH 28 (29 TRANSACTION 30 ISOLATION LEVEL = SNAPSHOT,31 LANGUAGE = N'us_english'32 )33 34 DECLARE @i INT = 035 36 WHILE @i < 100000037 BEGIN38 INSERT INTO dbo.TestTable (Col1, Col2, Col3) VALUES (@i,@i, @i)39 40 SET @i += 141 END42 END43 GO
我們繼續執行這個存儲過程:
1 SET STATISTICS TIME ON2 3 EXEC dbo.InsertTestData
執行同個存儲過程只需要780毫秒,與第一次用1024個桶數的測試運行,這已經是天大的區別。你也可以用DMVsys.dm_db_xtp_hash_index_stats來看下在你的哈希索引里有幾桶被使用:
1 SELECT * FROM sys.dm_db_xtp_hash_index_stats
這個測試告訴我們什么呢?要為Hekaton的哈希索引的存儲桶數,要做出正確的選擇,因為它們會大大影響SQL Server的性能!最佳桶數應該是在哈希索引里不同值的個數——另外要保留一些可用空間(在不同值個數上稍加),安全起見。你也不能把選擇太高的存儲桶數,因為相反你就在浪費內存。在SQL Server里的幾乎每個設置——都是基于你的工作量的而定,數據庫收縮除外哦!
感謝關注!
新聞熱點
疑難解答