SQL Server のクエリ通知 をメモリ最適化テーブルで使えるか試してみます。
クエリ通知は、ざっくり言うと、データの変更を検知し、SQL Server からクライアントに通知を行ってくれる機能です。
まず DB を作ります。
CREATE DATABASE [db1] ON PRIMARY ( NAME = N'db1', FILENAME = N'C:\DATA\db1.mdf', SIZE = 5120KB , FILEGROWTH = 1024KB ), FILEGROUP [MemoryOptimizedFG] CONTAINS MEMORY_OPTIMIZED_DATA ( NAME = N'MemoryOptimizedFile', FILENAME = N'C:\DATA\MemoryOptimizedFile' ) LOG ON ( NAME = N'db1_log', FILENAME = N'C:\DATA\db1_log.ldf', SIZE = 1024KB , FILEGROWTH = 10%)
Service Broker を有効にします。
alter database db1 set enable_BROKER with rollback immediate
で、メモリ最適化テーブルを用意します。
CREATE TABLE [dbo].[MemTable] ( [Id] int NOT NULL, [Name] nvarchar(20) NOT NULL PRIMARY KEY NONCLUSTERED HASH ([Id]) WITH (BUCKET_COUNT = 10000000) ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)
クエリ通知の検証用に通常のテーブルも作っときます。
CREATE TABLE [dbo].[NormalTable] ( [Id] int not null primary key, [Name] nvarchar(20) not null )
クエリ通知を有効化するための設定
クエリ通知の有効化
CREATE QUEUE ChangeData; CREATE SERVICE DataChangeNotifications ON QUEUE ChangeData ([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]);
通知されるアプリはこちら。
using System; using System.Data.SqlClient; using System.Diagnostics; using System.Threading.Tasks; namespace QueryNotify { class Subscriber : IDisposable { private const string ConnStr = @"Data Source=(local)\MSSQL2014;Initial Catalog=db1;Integrated Security=True"; private const string Query = @"select [Id], [Name] from [dbo].[MemTable] order by [Id]"; public void Initialize() { SqlDependency.Stop(ConnStr); SqlDependency.Start(ConnStr); } public async Task WriteData() { using (var conn = new SqlConnection(ConnStr)) using (var cmd = new SqlCommand(Query, conn)) { var dependency = new SqlDependency(cmd); dependency.OnChange += DependencyOnOnChange; await conn.OpenAsync(); using (var reader = await cmd.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { Console.WriteLine("Id:{0} Name;{1}", await reader.GetFieldValueAsync<object>(0), await reader.GetFieldValueAsync<object>(1)); } } } } private void DependencyOnOnChange(object sender, SqlNotificationEventArgs e) { var dependency = (SqlDependency)sender; dependency.OnChange -= DependencyOnOnChange; Debug.WriteLine("Info:{0} Source:{1} Type:{2}", e.Info, e.Source, e.Type); WriteData().Wait(); } public void Dispose() { SqlDependency.Stop(ConnStr); } } class Program { static void Main(string[] args) { using (var s = new Subscriber()) { s.Initialize(); s.WriteData().Wait(); Console.ReadKey(); } } } }
de:code でジニアスのセッションを見たので async/await 使ってみました。
それ以外は何てことないクエリ通知のサンプルです。
でこれを動かすと、エラーは出ないものの通知を検知してくれません。
ためしに、通常のテーブルに変更する*1とちゃんと通知してくれます。
メモリ最適化テーブルは、SCHEMA_ONLY/SCHEMA_AND_DATA 両方試しましたがダメでした。
SCHEMA_ONLY なメモリ最適化テーブルで使えると面白そうだったんですけどねー。
クエリ通知の注意事項はこちら
クエリ通知を使用するときの特別な注意事項 (ADO.NET)
SQL Server がローカルシステムアカウントで動いてたり、クライアントが Win95/98 だとダメだったりします。
他にも利用出来るクエリに制限があります。
3年ほど前ですが、クエリ通知の発表してたみたいです。
クエリ通知使ってみよう from Oda Shinsuke
*1:Query の from を MemTable -> NormalTable