SQLCLR トリガーをすぐに展開するのではなく、通常のトリガーから SQLCLR ストアド プロシージャを呼び出す利点はありますか?
まあ、いくつかの違いがあります。これらの違いがメリットまたはデメリットにどのように関係するかは、それぞれの状況の詳細によって異なります。
SQLCLR オブジェクト (ストアド プロシージャまたは関数) を呼び出す T-SQL トリガー
T-SQL トリガーは、次のようなクエリを使用して、どのテーブルにアタッチされているかを判断できます。
SELECT ss.[name] AS [SchemaName], so.[name] AS [TableName]
FROM [sys].[objects] so
INNER JOIN [sys].[schemas] ss ON ss.[schema_id] = so.[schema_id]
WHERE so.[object_id] = (SELECT so2.[parent_object_id]
FROM [sys].[objects] so2
WHERE so2.[object_id] = @@PROCID);
INSERTED
T-SQL トリガーから呼び出された SQLCLR オブジェクトは、および疑似テーブルに直接アクセスできませんDELETED
(これは、T-SQL ストアド プロシージャや呼び出しにも当てはまりEXEC()
ます)。これらのテーブルをローカルの一時テーブルにコピーして、SQLCLR オブジェクト (または T-SQL ストアド プロシージャまたはEXEC()
呼び出し) から読み取ることができますが、疑似オブジェクトから読み取るテーブルを作成するには、かなりの時間と I/O が必要です。 -table(s) に再度書き込みtempdb
ます。
SQLCLR トリガー
INSERTED
SQLCLR トリガーは、動的 SQL を介しておよびDELETED
疑似テーブルとやり取りできます (T-SQL トリガーではできないことです)。もちろん、そもそも SQLCLR コードがSELECT
疑似テーブルから取得する必要がある場合は、SQLCLR トリガーを使用する必要があります (それ以外の場合は、愚かな copy-pseudo-tables-to-local-temp-tables トリックを実行します)。
SQLCLR トリガーは( using を@@PROCID
作成したとしても) アクセスできないため、どのテーブルが変更されてトリガーが起動されたかを特定する簡単な方法はありません。テーブルの「最初の」トリガーとして設定されたT-SQLトリガーを使用してテーブル名を設定することは可能であるため(テストしていませんが)、「簡単」を強調しましたが、使用することはできません他のもののために。おそらく、私がほぼ解決したが、まだテストしていない別の方法があります(テストする機会があれば、機能する場合は、ここで手順へのリンクを更新することを忘れないでください)。SqlConnection
Context Connection = true;
CONTEXT_INFO
CONTEXT_INFO
非常に大きなテーブルで特定の列の変更 (StatusID) について通知を受ける必要があります。現在、多数の Windows サービスが使用されています。それぞれが独自の StatusID を監視します。つまり、特定の StatusID を db に問い合わせます: SELECT a,b,c FROM t WHERE StatusID = @status.
これは、SQLCLR を使用しなくても、確実にうまく処理できます。SQLCLR は優れた機能ですが、必要に応じて使用する必要があります。この場合、変更された行のテーブルの PK 列を記録するキュー テーブルのみが必要です。
CREATE TABLE dbo.TableChangeQueue
(
TableChangeQueueID INT IDENTITY(-2140000000, 1)
NOT NULL
CONSTRAINT [PK_TableChangeQueue] PRIMARY KEY,
[a] datatype_a,
[b] datatype_b,
[c] datatype_c
);
次に、通常の T-SQL トリガーを使用INSERT
してそのキューに入れます。次のようなもの:
INSERT INTO dbo.TableChangeQueue ([a], [b], [c])
SELECT [a], [b], [c]
FROM INSERTED;
その後、各 Windows サービスはキュー テーブル (大きなテーブルではありません) から読み取ることができます。レコードが処理されたら、その値に基づいてキュー テーブルから削除しTableChangeQueueID
ます。OUTPUT
ステートメントの句を使用して、それらを読み取り、同時に削除することもできますDELETE
が、プロセスが失敗した場合、それらを再処理する機能を失いたくないでしょう。
もちろん、これは単純な実装であり、これらの行が処理される前に複数回更新された場合、重複するキー エントリが許可されます。それが問題である場合 (つまり、キー値を一意にする必要がある場合)、トリガーでそれを処理する方法があります。問題が発生しない限り、トリガーが Windows サービスによって処理されているデータを変更しないように注意してください。
ここには多くのオプションがありますが、プロセスがどのように機能するかを知らずに特定することはできません. ただし、重要なポイントは、変更されたStatusID
s の処理を DML ステートメントから分離することです。これは、トリガーが内部のシステム生成トランザクション内で実行されるためです。これが、トリガーが完了するまでトランザクションが完了しないため、テーブルのブロックを簡単に増加させる可能性があるため、このトリガーの一部として変更された行をすぐに処理したくない理由です。トリガー エラーが発生した場合、DML ステートメントはロールバックされます。