17

SQL2005データベースに負荷の高い(多くの挿入/更新/削除)テーブルがあります。これらすべての変更に対して、可能な限りリアルタイムに近い状態で後処理を実行したいと思います(テーブルをロックしないように非同期で)。私はいくつかの可能な解決策を探しましたが、正しいと感じる1つのきちんとした解決策を見つけることができないようです。

後処理の種類もかなり重いので、Windowsリスナーサービスは実際に処理を多くのマシンに渡します。ただし、アプリケーションのこの部分はすでに稼働しており、完全に非同期であり、私が支援を必要としているものではありません-これは、CLRオブジェクトをロードすることができないという点で、設計上の決定に影響を与えるという理由だけで言及したいと思います処理を完了するためのDB。

したがって、単純な問題が残ります。テーブル内のデータが変更された場合、リモートサーバー上のc#コードで処理を実行したいと思います。

現在、「xp_cmdshell」を実行してWindowsサービスがリッスンしているイベントを発生させるexeを起動するSQLトリガーを使用することを考え出しました。これはただ気分が悪い。

しかし、私がオンラインで調べた他のソリューションもかなり複雑に感じます。たとえば、SQLCacheDependancyの設定には、ServiceBrokerの設定も含まれます。もう1つの可能な解決策は、Webサービスを呼び出すことができるCLRトリガーを使用することですが、これには、特にパフォーマンスが重要な場合に、それを実行するのに悪い方法であるという警告がオンラインで非常に多くあります。

理想的には、テーブルの変更に依存せず、アプリケーション内の呼び出しをインターセプトしてそこからサービスに通知します。残念ながら、一部のレガシーアプリケーションもデータに変更を加えており、テーブルの監視は瞬間。

どんな助けでも大歓迎です。

概要:

  • テーブルデータの変更にリアルタイムで対応する必要があります
  • パフォーマンスは重要です
  • 大量のトラフィックが予想されます
  • ポーリングとスケジュールされたタスクはオプションではありません(またはリアルタイム)
  • サービスブローカーの実装が大きすぎます(ただし、解決策にすぎない可能性がありますか?)
  • CLRコードはまだ除外されていませんが、提案された場合は実行する必要があります
  • リスナー/モニターはリモートマシンである可能性があります(同じ物理ネットワークである可能性があります)
4

5 に答える 5

20

SQL 2005の変更を検出する方法は、実際にはそれほど多くありません。すでにほとんどの方法をリストしています。

クエリ通知。これは、SqlDependencyとその派生物を強化するテクノロジーです。詳細については、TheMysteriousNotificationを参照してください。ただし、QNは結果を無効にするように設計されており、変更内容を事前に通知することはありません。何が変更されたかを知ることなく、テーブルに変更があることだけがわかります。ビジーなシステムでは、通知がほぼ継続的に送信されるため、これは機能しません。

ログの読み取り。これはトランザクションレプリケーションが使用するものであり、変更を検出するための最も邪魔にならない方法です。残念ながら、内部コンポーネントでのみ使用できます。ログの形式を理解できたとしても、問題は、ログを読み取るまでログを「使用中」としてマークするためにエンジンからのサポートが必要なことです。そうしないと、ログが上書きされる可能性があります。この種の特別なマーキングを実行できるのは、トランザクションレプリケーションのみです。

データ比較。変更を検出するには、タイムスタンプ列に依存します。また、プルベースであり、非常に煩わしく、削除の検出に問題があります。

アプリケーション層。これは理論的には最良のオプションです。ただし、アプリケーションの範囲外でデータに変更が発生した場合は、データが崩れます。実際には、アプリケーションの範囲外で常に変更が発生します。

トリガー。最終的に、これが唯一の実行可能なオプションです。トリガーに基づくすべての変更メカニズムは同じように機能し、キューを監視するコンポーネントに変更通知をキューに入れます。

緊密に結合された同期通知(xp_cmdshell、xp_olecreate、CLR、WCFで通知、名前を付ける)を行うための提案は常にありますが、これらのスキームはすべて、根本的に欠陥があるため実際には失敗します:
-トランザクションの一貫性を考慮していませんロールバック
-可用性の依存関係を導入します(通知されたコンポーネントがオンラインでない限り、OLTPシステムは続行できません)
-各DML操作は、何らかの形式のRPC呼び出しが完了するのを待たなければならないため、ひどく実行されます

トリガーが実際にリスナーにアクティブに通知せず、通知をキューに入れるだけの場合、通知キューの監視に問題があります(「キュー」と言うときは、キューとして機能するテーブルを意味します)。監視とは、キュー内の新しいエントリをプルすることを意味します。つまり、チェックの頻度と変更の負荷のバランスを正しく取り、負荷の急増に対応することを意味します。これは決して些細なことではなく、実際には非常に困難です。ただし、SQLサーバーには、変更が利用可能になるまでプルせずにブロックするセマンティクスを持つステートメントが1つあります:WAITFOR(RECEIVE)。それはサービスブローカーを意味します。あなたはあなたの投稿でSSBについて何度か言及しましたが、当然のことながら、大きな未知数のためにSSBを配備することを恐れています。しかし、現実には、それがあなたが説明したタスクにはるかに最適であるということです。

通知がリモートサービスに完全に配信される完全なSSBアーキテクチャをデプロイする必要はありません(とにかく、ExpressインスタンスであってもリモートSQLインスタンスが必要になります)。共犯する必要があるのは、変更が検出された瞬間(DMLトリガー)を通知が配信された瞬間(変更がコミットされた後)から切り離すことです。このために必要なのは、ローカルSSBキューとサービスだけです。トリガーで、変更通知をローカルサービスに送信します。元のDMLトランザクションがコミットされた後、サービスプロシージャは、たとえばCLRを使用して、通知をアクティブ化して配信します。Asynchronous T-SQLで、これに似た例を見ることができます。

その道を進むと、高いスループットを達成するために学ぶ必要のあるいくつかのトリックがあり、SSBでのメッセージの順序付けられた配信の概念を理解する必要があります。これらのリンクをお読みになることをお勧めします。

変更を検出する手段について、SQL2008は明らかに新しいオプションを追加します:変更データキャプチャと変更追跡。それらは実際には新しいテクノロジーではないので、私は「明らかに」を強調します。CDCはログリーダーを使用し、既存のトランザクションレプリケーションメカニズムに基づいています。CTはトリガーを使用し、既存のマージレプリケーションメカニズムと非常によく似ています。これらは両方とも、同期する必要があるため、リアルタイムの変更通知には適さない、時々接続されるシステムを対象としています。それらは変更テーブルにデータを入力できますが、変更がないかこれらのテーブルを監視するタスクが残ります。これは、開始した場所から正確に行われます。

于 2009-10-13T18:24:59.410 に答える
1

これは多くの方法で行うことができます。以下の方法は、CLRトリガーとsqlcmdオプションを使用したくないので簡単です。

  • CLRトリガーを使用する代わりに、各挿入の専用追跡テーブルを更新する通常の挿入トリガーを作成できます。

  • また、追跡テーブルをアクティブにポーリングし、データに変更があった場合はリモートサービスを更新し、追跡テーブルのステータスを完了に設定する専用のウィンドウサービスを開発します(これにより、再度選択されることはありません)。

編集:

ADO.Net用のMicrosoft同期サービスが機能すると思います。以下のリンクをチェックしてください。それはあなたを助けるかもしれません

于 2009-10-13T11:31:35.297 に答える
0

同様の状況で、キュー(MSMQ)にメッセージを書き込むCLRトリガーを使用しています。C#で記述されたサービスは、キューを監視し、後処理を実行しています。この場合、すべて同じサーバーで実行されますが、「ローカルリスナー」を完全にバイパスして、これらのメッセージを別のマシンのリモートキューに直接送信できます。

トリガーから呼び出されるコードは次のようになります。

public static void SendMsmqMessage(string queueName, string data)
{
    //Define the queue path based on the input parameter.
    string QueuePath = String.Format(".\\private$\\{0}", queueName);

    try
    {
        if (!MessageQueue.Exists(QueuePath))
            MessageQueue.Create(QueuePath);

        //Open the queue with the Send access mode
        MessageQueue MSMQueue = new MessageQueue(QueuePath, QueueAccessMode.Send);

        //Define the queue message formatting and create message
        BinaryMessageFormatter MessageFormatter = new BinaryMessageFormatter();
        Message MSMQMessage = new Message(data, MessageFormatter);

        MSMQueue.Send(MSMQMessage);
    }
    catch (Exception x)
    {
        // async logging: gotta return from the trigger ASAP
        System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(LogException), x);
    }
}
于 2009-10-13T20:49:53.877 に答える
-1

そのテーブルで実行されている挿入が多いと言ったので、バッチ処理の方が適している可能性があります。

フラグ列で識別される新しいデータを処理し、データを大きなチャンクで処理するスケジュールされたジョブを作成したのはなぜですか?

于 2009-10-13T11:21:01.217 に答える
-1

通常のトリガーを使用して、データベースでCLRを起動します。このCLRは、Win32_Processクラスを使用してリモートでのみプログラムを開始します。

http://motevich.blogspot.com/2007/11/execute-program-on-remote-computer.html

于 2009-10-13T14:02:22.867 に答える