转载

在Hekaton里,正确选择哈希存储桶数

今天我使用2048的桶数的哈希索引,往Hakaton里插入100万的记录,测试下在哈希桶数里, 哈希冲突(Hash Collision) 是如何影响Hekaton的工作量——结果非常非常有意思。首先我想介绍下什么是哈希冲突。

你可能知道(非常希望),在SQL Server 2014里,Hakaton表是以 哈希索引(Hash Indexes) 实现的。 维基百科对此有详细介绍 ,这是哈希索引的应用基础。   哈希函数将索引键映射到哈希索引中对应的 Bucket,哈希函数的结果决定你的行最终放入那个哈希桶。如果多个键值哈希到同个值,SQL Server会在那个哈希桶里插入,在那个哈希桶有多个入口链接在一起。来看下面的图示( 来自维基百科 ):

在Hekaton里,正确选择哈希存储桶数

从图中可以看到,键值“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 HashCollisions 11 GO 12  13 -- Add a new file to the previous created file group 14 ALTER DATABASE HashCollisions ADD FILE 15 ( 16     NAME = N'HekatonContainer',  17     FILENAME = N'C:/Program Files/Microsoft SQL Server/MSSQL12.MSSQLSERVER/MSSQL/DATA/HashCollisionsContainer' 18 ) 19 TO FILEGROUP [HekatonFileGroup] 20 GO 21  22 -- Create a simple table 23 CREATE TABLE TestTable 24 ( 25     Col1 INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 1024), 26     Col2 INT NOT NULL, 27     Col3 INT NOT NULL 28 ) 29 WITH 30 ( 31     MEMORY_OPTIMIZED = ON,  32     DURABILITY = SCHEMA_ONLY 33 ) 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 = 0 17      18     WHILE @i < 1000000 19     BEGIN 20         INSERT INTO dbo.TestTable (Col1, Col2, Col3) VALUES (@i,@i, @i) 21  22         SET @i += 1 23     END 24 END 25 GO

可以看到,这里我用简单的循环来插入1000000条记录。在4核CPU,4G内存的虚拟机上,我们打开时间统计,来执行这个存储过程:

1 SET STATISTICS TIME ON 2  3 EXEC dbo.InsertTestData

在Hekaton里,正确选择哈希存储桶数

执行时间差不多有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 NULL 10 ) 11 WITH 12 ( 13     MEMORY_OPTIMIZED = ON,  14     DURABILITY = SCHEMA_ONLY 15 ) 16 GO 17  18  19 -- Create a native compiled Stored Procedure 20 CREATE PROCEDURE InsertTestData 21 WITH  22     NATIVE_COMPILATION,  23     SCHEMABINDING,  24     EXECUTE AS OWNER 25 AS  26 BEGIN 27     ATOMIC WITH  28     ( 29         TRANSACTION  30         ISOLATION LEVEL = SNAPSHOT, 31         LANGUAGE = N'us_english' 32     ) 33  34     DECLARE @i INT = 0 35      36     WHILE @i < 1000000 37     BEGIN 38         INSERT INTO dbo.TestTable (Col1, Col2, Col3) VALUES (@i,@i, @i) 39  40         SET @i += 1 41     END 42 END 43 GO

我们继续执行这个存储过程:

1 SET STATISTICS TIME ON 2  3 EXEC dbo.InsertTestData

在Hekaton里,正确选择哈希存储桶数

执行同个存储过程只需要780毫秒,与第一次用1024个桶数的测试运行,这已经是天大的区别。你也可以用DMV sys.dm_db_xtp_hash_index_stats来看下在你的哈希索引里有几桶被使用:

1 SELECT * FROM sys.dm_db_xtp_hash_index_stats

在Hekaton里,正确选择哈希存储桶数

这个测试告诉我们什么呢?要为Hekaton的哈希索引的存储桶数,要做出正确的选择,因为它们会大大影响SQL Server的性能!最佳桶数应该是在哈希索引里不同值的个数——另外要保留一些可用空间(在不同值个数上稍加),安全起见。你也不能把选择太高的存储桶数,因为相反你就在浪费内存。在SQL Server里的几乎每个设置——都是基于你的工作量的而定,数据库收缩除外哦!

感谢关注!

正文到此结束
Loading...