1

SQLCLR トリガーをすぐに展開するのではなく、通常の T-SQL トリガーから SQLCLR ストアド プロシージャを呼び出すことに利点はありますか?

StatusID非常に大きなテーブルで特定の列の変更 ( ) について通知を受ける必要があります。

現在、多くの Windows サービスが使用されています。それぞれが独自の StatusID を監視します。つまり、特定のStatusID:を db に照会しますSELECT a,b,c FROM t WHERE StatusID = @status

ロジックをサービスから SQLCLR アセンブリに移動し、SQLCLR トリガーを使用してそれらを呼び出したいと考えています。それは良い考えですか?より良いアイデアはありますか?

4

3 に答える 3

1

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);
    

    INSERTEDT-SQL トリガーから呼び出された SQLCLR オブジェクトは、および疑似テーブルに直接アクセスできませんDELETED(これは、T-SQL ストアド プロシージャや呼び出しにも当てはまりEXEC()ます)。これらのテーブルをローカルの一時テーブルにコピーして、SQLCLR オブジェクト (または T-SQL ストアド プロシージャまたはEXEC()呼び出し) から読み取ることができますが、疑似オブジェクトから読み取るテーブルを作成するには、かなりの時間と I/O が必要です。 -table(s) に再度書き込みtempdbます。

  • SQLCLR トリガー

    INSERTEDSQLCLR トリガーは、動的 SQL を介しておよびDELETED疑似テーブルとやり取りできます (T-SQL トリガーではできないことです)。もちろん、そもそも SQLCLR コードがSELECT疑似テーブルから取得する必要がある場合は、SQLCLR トリガーを使用する必要があります (それ以外の場合は、愚かな copy-pseudo-tables-to-local-temp-tables トリックを実行します)。

    SQLCLR トリガーは( using を@@PROCID作成したとしても) アクセスできないため、どのテーブルが変更されてトリガーが起動されたかを特定する簡単な方法はありません。テーブルの「最初の」トリガーとして設定されたT-SQLトリガーを使用してテーブル名を設定することは可能であるため(テストしていませんが)、「簡単」を強調しましたが、使用することはできません他のもののために。おそらく、私がほぼ解決したが、まだテストしていない別の方法があります(テストする機会があれば、機能する場合は、ここで手順へのリンクを更新することを忘れないでください)。SqlConnectionContext Connection = true;CONTEXT_INFOCONTEXT_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 サービスによって処理されているデータを変更しないように注意してください。

ここには多くのオプションがありますが、プロセスがどのように機能するかを知らずに特定することはできません. ただし、重要なポイントは、変更されたStatusIDs の処理を​​ DML ステートメントから分離することです。これは、トリガーが内部のシステム生成トランザクション内で実行されるためです。これが、トリガーが完了するまでトランザクションが完了しないため、テーブルのブロックを簡単に増加させる可能性があるため、このトリガーの一部として変更された行をすぐに処理したくない理由です。トリガー エラーが発生した場合、DML ステートメントはロールバックされます。

于 2016-07-05T20:20:59.207 に答える
1

私の意見では、これには SQLCLR は必要ありません。ただし、「通知される」の意味によって異なります。可能であれば、通常のトリガーと SQL エージェント ジョブを使用して通知を行います。

于 2010-07-22T18:13:46.370 に答える
0

CLRから直接サービスを呼び出す場合、CLRは.NET 2.0スタイルのWeb参照のみをサポートするため、標準のSOAPバインディングを使用する必要があります。

SQL Serverサービスブローカーを使用する方がより堅牢なソリューションですが、ご指摘のとおり、複雑です。SQLCLRを使用するために支払う代償は、トリガーから未処理のエラーがスローされた場合に更新トランザクションがロールバックされることです。また、更新のたびにサービスコールをブロックしている場合、トランザクションスループットは確実に影響を受けます。

于 2010-07-24T06:18:50.370 に答える