Memory Optimized Table (メモリ最適化テーブル / Hekaton) ではハッシュインデックスが使用されており、作成時に BUCKET_COUNT (バケットカウント) を指定し、ハッシュインデックスはこのバケットの中に格納されていくことになります。
このバケットカウントと性能への影響について少しまとめてみたいと思います。
バケットカウントは 1 バケットで 8 バイト (レコードのポインタ分) 必要となり、バケットカウントに指定した分のメモリは格納しているデータの件数にかかわらず確保されることになります。
# バケットは 2 の累乗のサイズで取得されるため、適当な数値を入れても近い累乗値に丸められます。
また、現在の Memory Optimized Table では、テーブル作成後にインデックス定義を含めたテーブル定義を変更することができませんので、サイズを変えたい場合にはテーブルを再作成する必要があるため、設計時のどれくらいのデータを格納するかを考慮したうえで設定をする必要があります。
Memory Optimized Table の最大サイズは 256GB で、max server memory の 80% がメモリの制限となるようですので設計ではこれを上限として考える必要もありますが。
Requirements for Using Memory-Optimized Tables
Hardware Considerations for In-Memory OLTP in SQL Server 2014
単一のテーブルに対してデータを挿入する場合などは、バケットのサイズが性能に大きく影響してくるようです。
以下のようなテーブルとストアドプロシージャを作成してみます。
# 高速にデータ挿入を行いたいため、DURABILITY の設定は SCHEMA_ONLY にしています。これによりディスク書き込みが抑制されますのでデータ作成を高速に行えます。
CREATE TABLE MemTable4096 ( Col1 int NOT NULL, Col2 nchar(36) COLLATE Japanese_XJIS_100_BIN2 NOT NULL, Col3 int NOT NULL, Col4 nchar(36)? COLLATE Japanese_XJIS_100_BIN2 CONSTRAINT PK_MemTable2 PRIMARY KEY NONCLUSTERED HASH (Col1) WITH (BUCKET_COUNT = 4096) ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY) GOCREATE PROCEDURE NativeSP1 @datacount int WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER AS BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N’japanese’ ) DELETE FROM dbo.MemTable1024 DECLARE @i int, @cnt int = 1 SELECT @i = ISNULL(MAX(Col1), 0) + 1 FROM dbo.MemTable1024 WHILE (@cnt <= @datacount) BEGIN INSERT INTO dbo.MemTable1024 VALUES(@i, N’AAAA’, @i, N’BBBBB’) SET @i += 1 SET @cnt += 1 END END GO |
上記のテーブルはバケットカウントを 1024 に設定していますが、バケットカウントを変更した同一定義のテーブルとストアドプロシージャを作成して、1,000,000 (100 万件) のデータを挿入 (EXEC NativeSP1 1000000) して、処理時間を計測してみたいと思います。
以下のバケットカウントは実運用では設定しないと思われる小さい値を設定しています。
1バケット8バイトですので、実際の運用では大きめなバケットサイズを設定しても消費メモリはそれほど多くありませんので、実際に使用される際にはかなり大き目なサイズを設定してもメモリ消費の影響は少ないと思います。
バケットカウント | バケットの利用メモリ | 処理時間 |
1,024 | 8KB | 5:34 |
4,096 | 32KB | 0:32 |
8,192 | 64KB | 0:15 |
16,384 | 128KB | 0:08 |
1,048,576 | 8MB | 0:01 |
同一のクエリを使用してデータを挿入していますが、バケットカウントによって処理時間に大きく差が出てきていますね。細かな挙動までは確認ができていないのですが、ハッシュインデックスのバケットのサイズが不足し、バケット内のメンテナンスが必要となった分のオーバーヘッドでしょうか。
SELECT に関しては、結果がわかりやすいテストパターンが作れていないので影響は見れていないのですが、仕組みを考慮すると Seek 時の性能には影響するのではと思っています。
バケットカウントの調整は Memory Optimized Table のチューニングの考慮点となりそうですね。