150

トリガーを使用したり、データベースの構造を変更したりせずに、SQL Serverデータベースのテーブルへの変更を監視するにはどうすればよいですか?私が好むプログラミング環境は.NETとC#です。

SQL Server2000SP4以降をサポートできるようにしたいと思います。私のアプリケーションは、他社製品のボルトオンデータ視覚化です。私たちの顧客ベースは数千人にのぼるので、インストールのたびにサードパーティベンダーのテーブルを変更するという要件を課す必要はありません。

テーブルへの変更」とは、テーブル構造の変更ではなく、テーブルデータの変更を意味します。

最終的には、変更を定期的にチェックするのではなく、アプリケーションでイベントをトリガーするように変更したいと思います。


私の要件(トリガーやスキーマの変更なし、SQL Server 2000および2005)を考えると、最善の行動はT-SQLBINARY_CHECKSUMの関数を使用することのようです。私が実装する予定の方法は次のとおりです。

X秒ごとに、次のクエリを実行します。

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))
FROM sample_table
WITH (NOLOCK);

そして、それを保存された値と比較します。値が変更された場合は、クエリを使用してテーブルを1行ずつ調べます。

SELECT row_id, BINARY_CHECKSUM(*)
FROM sample_table
WITH (NOLOCK);

そして、返されたチェックサムを保存されている値と比較します。

4

8 に答える 8

100

CHECKSUMコマンドを見てください。

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);

テーブルの内容が変更されていない限り、実行するたびに同じ番号が返されます。詳細については、これに関する私の投稿を参照してください。

チェックサム

テーブルが変更されたときにキャッシュの依存関係を再構築するためにこれを使用した方法は次のとおりです
。ASP.NET1.1データベースのキャッシュの依存関係(トリガーなし)

于 2008-08-02T05:20:22.397 に答える
30

残念ながら、CHECKSUMは変更を検出するために常に正しく機能するとは限りません

これは基本的なチェックサムであり、巡回冗長検査(CRC)の計算ではありません。

したがって、これを使用してすべての変更を検出することはできません。たとえば、対称的な変更は同じチェックサムになります。

例:のソリューションは、CHECKSUM_AGG(BINARY_CHECKSUM(*))コンテンツが異なる3つのテーブルすべてに対して常に0を配信します。


SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM 
(
  SELECT 1 as numA, 1 as numB
  UNION ALL
  SELECT 1 as numA, 1 as numB
)  q
-- delivers 0!

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 1 as numA, 2 as numB UNION ALL SELECT 1 as numA, 2 as numB ) q -- delivers 0!

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 0 as numA, 0 as numB UNION ALL SELECT 0 as numA, 0 as numB ) q -- delivers 0!

于 2011-03-30T12:07:06.750 に答える
24

トリガーを使いたくないのはなぜですか?正しく使えばいいですね。それらを良いものから悪いものへと変化するときの参照整合性を強制する方法として使用する場合。しかし、それらを監視に使用する場合、それらは実際にはタブーとは見なされません。

于 2008-08-01T13:07:52.810 に答える
20

変更を確認する必要がある頻度と、データベース内のテーブルの大きさ(行サイズの観点から)はどれくらいですか?CHECKSUM_AGG(BINARY_CHECKSUM(*))Johnが提案した方法を使用すると、指定したテーブルのすべての行がスキャンされます。NOLOCKヒントは役に立ちますが、大規模なデータベースでは、まだすべての行にヒットしています。また、すべての行のチェックサムを保存して、1つが変更されたことを通知する必要があります。

別の角度からこれに取り組むことを検討しましたか?スキーマを変更してトリガーを追加したくない場合(これは理にかなっていますが、データベースではありません)、データベースを作成しているアプリケーションベンダーと協力することを検討しましたか?

データが変更されたことをアクセサリアプリに通知するメカニズムを提供するAPIを実装できます。どのテーブルとどの行が変更されたかをリストする通知テーブルに書き込むのと同じくらい簡単かもしれません。これは、トリガーまたはアプリケーションコードを介して実装できます。あなたの側から見ると、tiは重要ではありません。あなたの唯一の関心事は、定期的に通知テーブルをスキャンすることです。データベースのパフォーマンスへの影響は、すべての行をスキャンして変更を探すよりもはるかに少なくなります。

難しいのは、アプリケーションベンダーにこの機能を実装するよう説得することです。これはトリガーを介してSQLを介して完全に処理できるため、トリガーを記述してテストし、コードをアプリケーションベンダーに提供することで、大部分の作業を行うことができます。ベンダーにトリガーをサポートさせることで、トリガーを追加すると、ベンダーが提供するトリガーが誤って置き換えられる状況を防ぐことができます。

于 2008-08-03T13:59:24.063 に答える
18

残念ながら、SQL2000でこれを行うためのクリーンな方法はないと思います。要件をSQLServer2005(およびそれ以降)に絞り込むと、ビジネスになります。SQLDependencyでクラスを使用できますSystem.Data.SqlClientSQL Server(ADO.NET)でのクエリ通知を参照してください。

于 2008-08-06T01:54:21.687 に答える
16

指定された間隔で実行されるDTSジョブ(またはWindowsサービスによって開始されるジョブ)があります。実行されるたびに、システムINFORMATION_SCHEMAテーブルを使用して、指定されたテーブルに関する情報を取得し、このデータをデータリポジトリに記録します。テーブルの構造に関して返されたデータを、前回返されたデータと比較します。異なる場合は、構造が変更されていることがわかります。

テーブルABCのすべての列に関する情報を返すクエリの例(理想的には、ここで行うように* select **を使用する代わりに、必要なINFORMATION_SCHEMAテーブルの列のみを一覧表示します)。

select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'

「テーブルへの変更」をどの程度正確に定義するかに応じて、さまざまな列とINFORMATION_SCHEMAビューを監視します。

于 2008-08-01T14:06:28.560 に答える
13

ここでの大げさな推測:サードパーティのテーブルを変更したくない場合は、ビューを作成してから、そのビューにトリガーを設定できますか?

于 2008-08-05T01:12:37.527 に答える
7

最終コミット日を確認してください。すべてのデータベースには、各コミットが行われたときの履歴があります。私はそれがACIDコンプライアンスの基準であると信じています。

于 2014-07-24T04:58:25.450 に答える