130


24

SQL Serverテーブルへの変更を確認しますか?

トリガーを使用したりデータベースの構造を変更したりすることなく、テーブルへの変更についてSQL Serverデータベースを監視する方法を教えてください。 私が好むプログラミング環境はhttp://en.wikipedia.org/wiki/.NET_Framework[.NET]とC#です。

SQL Server 2000 SP4以降のいずれかをサポートできるようにしたいです。 私のアプリケーションは、他社製品のボルトオンデータ視覚化です。 私達の顧客基盤は数千にあります、従って私は私達があらゆる設置で第三者の製造業者のテーブルを修正するという要件を入れる必要はありません。

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

最終的には、一定の間隔で変更を確認するのではなく、変更をアプリケーション内でイベントをトリガーすることを望みます。

'' '' '

私の要件(トリガーやスキーマの変更、SQL Server 2000、2005なし)を考えた場合の最善の策は、http://en.wikipedia.org/wiki/Transact-SQL [T-]の `BINARY_CHECKSUM`関数を使うことです。 SQL]。 私が実装する予定の方法はこれです:

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

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

そしてそれを格納されている値と比較します。 値が変更されている場合は、クエリを使用してテーブルを1行ずつ移動します。

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

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

8 Answer


94


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

sample_tablewith(NOLOCK)からのSELECT CHECKSUM_AGG(BINARY_CHECKSUM(*));

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

http://msdn.microsoft.com/ja-jp/library/aa258245(SQL.80).aspx[CHECKSUM]

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


30


残念ながら、CHECKSUMは変更を検出するために常に正しく動作しません。 これは基本的なチェックサムであり、CRC計算ではありません。 したがって、あなたはそれを使ってすべての変更を検出することはできません。 g. 対称的な変更は同じCHECKSUMになります。

  1. 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
(
  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!


26


トリガーを使いたくないのはなぜですか。 あなたがそれらを正しく使用すればそれらは良いことです。 参照整合性を強制する方法としてそれらを使用すると、それはそれらが善から悪へと変わるときです。 しかし、あなたが監視のためにそれらを使うのであれば、それらは本当にタブーとは見なされません。


20


どのくらいの頻度で変更をチェックする必要がありますか。また、データベース内のテーブルのサイズ(行サイズ)はどれくらいですか。 Johnが提案した `CHECKSUM_AGG(BINARY_CHECKSUM(*))`メソッドを使うと、指定されたテーブルのすべての行をスキャンします。 `NOLOCK`ヒントは役に立ちますが、大規模なデータベースでは、まだすべての行にアクセスしています。 チェックサムを変更したことを知らせるために、チェックサムをすべての行に格納する必要もあります。

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

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

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


18


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

テーブルABC内のすべての列に関する情報を返すためのクエリの例(ここで行うように* select **を使用するのではなく、理想的には、必要なINFORMATION_SCHEMAテーブルからの列のみを一覧表示する):

INFORMATION_SCHEMA.COLUMNSから*を選択します。TABLE_NAME = 'ABC'

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


18


残念ながら、私はこれをSQL2000できれいにする方法があるとは思わない。 要件をSQL Server 2005(およびそれ以降)に絞り込んだ場合、あなたはビジネスを始めます。 System.Data.SqlClient`で SQLDependency`クラスを使うことができます。 http://msdn.microsoft.com/ja-jp/library/t9x04ed2.aspx [SQL Serverのクエリ通知(ADO.NET)]を参照してください。


13


あなたがここでワイルド推測する:もしあなたが第三者のテーブルを修正したくないのなら、あなたはビューを作成してからそのビューにトリガーをかけることができますか?


6


最後のコミット日を確認してください。 各データベースには、各コミットが行われたときの履歴があります。 私はその規格がACIDに準拠していると信じています。