SQL Server テーブルへの変更を確認しますか?
-
08-06-2019 - |
質問
トリガーを使用したりデータベースの構造を変更したりせずに、SQL Server データベースのテーブル変更を監視するにはどうすればよいですか?私の好みのプログラミング環境は 。ネット そしてC#。
何かあればサポートさせていただきたいと思います SQLサーバー2000 SP4以降。私のアプリケーションは、他社製品のボルトオン データ視覚化です。当社の顧客ベースは数千に及ぶため、インストールのたびにサードパーティ ベンダーのテーブルを変更するという要件を課す必要はありません。
による 「テーブルに変更」 テーブル構造の変更ではなく、テーブル データの変更を意味します。
最終的には、一定の間隔で変更を確認するのではなく、変更によってアプリケーション内でイベントがトリガーされるようにしたいと考えています。
私の要件 (トリガーやスキーマの変更なし、SQL Server 2000 および 2005) を考慮した最善の行動は、 BINARY_CHECKSUM
で機能する T-SQL. 。私が実装する予定の方法は次のとおりです。
X 秒ごとに次のクエリを実行します。
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))
FROM sample_table
WITH (NOLOCK);
そしてそれを保存された値と比較します。値が変更されている場合は、次のクエリを使用してテーブルを行ごとに調べます。
SELECT row_id, BINARY_CHECKSUM(*)
FROM sample_table
WITH (NOLOCK);
そして、返されたチェックサムを保存された値と比較します。
解決
CHECKSUM コマンドを見てください。
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);
テーブルの内容が変更されない限り、実行されるたびに同じ数値が返されます。詳細については、これに関する私の投稿を参照してください。
これを使用して、テーブルが変更されたときにキャッシュの依存関係を再構築する方法を次に示します。
ASP.NET 1.1 データベース キャッシュの依存関係 (トリガーなし)
他のヒント
残念ながら、CHECKSUM は変更を検出するために常に適切に機能するとは限りません.
これは基本的なチェックサムのみであり、巡回冗長検査 (CRC) の計算はありません。
したがって、これを使用してすべての変更を検出することはできません。g.対称的な変更は同じ CHECKSUM になります。
E.g.による解決策 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(numa、2 as numb select 1 as numa、2 as numb as numb)q -divers 0を選択します。
select checksum_agg(binary_checksum(*))from(numa、0 as numb union all select as numa、0 as numb)q -divers 0を選択します。
なぜトリガーを使用しないのでしょうか?正しく使えば良いものです。参照整合性を強制する方法としてそれらを使用すると、それらは良い状態から悪い状態に変わります。ただし、モニタリングに使用する場合は、実際にはタブーとはみなされません。
変更を確認する頻度はどれくらいですか?また、データベース内のテーブルの大きさ (行サイズに関して) はどれくらいですか?を使用する場合は、 CHECKSUM_AGG(BINARY_CHECKSUM(*))
John が提案した方法では、指定されたテーブルのすべての行をスキャンします。の NOLOCK
ヒントは役に立ちますが、大規模なデータベースでは依然としてすべての行にヒットします。また、行ごとにチェックサムを保存して、行が変更されたことがわかるようにする必要があります。
別の角度からこれに取り組むことを検討しましたか?トリガーを追加するためにスキーマを変更したくない場合 (これは当然のことですが、データベースではありません)、データベースを作成するアプリケーション ベンダーと協力することを検討しましたか?
データが変更されたことをアクセサリ アプリに通知するメカニズムを提供する API を実装することもできます。どのテーブルとどの行が変更されたかをリストする通知テーブルに書き込むだけの簡単な場合もあります。これは、トリガーまたはアプリケーション コードを通じて実装できます。あなたにとって、ti は問題ではありません。唯一の懸念は、通知テーブルを定期的にスキャンすることです。データベースのパフォーマンスへの影響は、すべての行をスキャンして変更を確認するよりもはるかに少なくなります。
難しいのは、アプリケーション ベンダーにこの機能を実装するよう説得することです。これはトリガーを介して SQL を通じて完全に処理できるため、トリガーを作成してテストし、コードをアプリケーション ベンダーに提供することで、作業の大部分を行うことができます。ベンダーにトリガーをサポートさせることで、トリガーを追加することでベンダーが提供するトリガーを誤って置き換えるという状況を防ぐことができます。
残念ながら、SQL2000 でこれを行うきれいな方法はないと思います。要件を SQL Server 2005 (以降) に絞り込めば、問題はありません。使用できます SQLDependency
クラスイン System.Data.SqlClient
. 。見る SQL Server のクエリ通知 (ADO.NET).
特定の間隔で実行される DTS ジョブ (または Windows サービスによって開始されるジョブ) を用意します。実行されるたびに、システムを使用して指定されたテーブルに関する情報を取得します。 INFORMATION_SCHEMA テーブルを作成し、このデータをデータ リポジトリに記録します。テーブルの構造に関して返されたデータを、前回返されたデータと比較します。異なる場合は、構造が変化したことがわかります。
テーブル ABC 内のすべての列に関する情報を返すクエリの例 (理想的には、ここで行うように *select ** を使用する代わりに、INFORMATION_SCHEMA テーブルから必要な列だけをリストします)。
select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'
「テーブルへの変更」をどの程度正確に定義するかに応じて、さまざまな列と INFORMATION_SCHEMA ビューを監視します。
ここでのワイルドな推測:サードパーティのテーブルを変更したくない場合は、ビューを作成して、そのビューにトリガーを設定できますか?
最終コミット日を確認してください。すべてのデータベースには、各コミットがいつ行われたかの履歴があります。これが ACID 準拠の標準だと思います。