年に約 5 回、最も重要なテーブルの 1 つに、すべての値が NULL に置き換えられる特定の列があります。これに対してログ エクスプローラーを実行しましたが、更新で入力されたログイン/ホスト名は確認できません。レコードが変更されたことだけが確認できます。サーバー上のすべてのデータベースで、このテーブルに触れるすべての更新ステートメントについて、すべての sproc、関数などを検索しました。テーブルには、この列に対する外部キー制約があります。これは更新中に確立される整数値ですが、更新は ID キー固有です。このフィールドにはインデックスもあります。t-sql update ステートメント以外でこれを引き起こしている可能性があるものについて何か提案はありますか?
3 に答える
可能であれば、クライアント側の動的 SQL を拒否することから始めます。ストアド プロシージャを監査して、適切な where 句を含む正しい SQL が実行されていることを確認する方がはるかに簡単です。SQLサーバーがひどく壊れていない限り、データが更新される唯一の方法は、それに対して実行しているSQLのためです。
すべてのストアド プロシージャ、スクリプトなどは、実行を許可する前に監査する必要があります。
動的クライアント sql を適用しないというモジョがない場合は、実行前に各クライアント sql をキャプチャするアプリケーション ログを追加します。個人的には、where 句が欠落している場合、ロギング ルーチンに (ロギング後に) 例外をスローさせるようにしますが、少なくとも、ログを確認することで、次回データがどこで吹き飛ばされるかを把握できるはずです。正確なソースを追跡できるように、ログに十分な情報が記録されていることを確認してください。実行可能な各動的SQLステートメントに一意の「名前」を割り当てます。たとえば、各プログラムに3文字のコードを割り当て、プログラム内の可能な各呼び出しに1..nnの番号を付けて、どの呼び出しがデータを爆破したかを知ることができます「abc123」と、欠陥のある正確なSQL。
コメントを追加
これは後で考えます。SQL テーブルの更新トリガーを追加/変更して、行数を確認し、行数が意味のあるしきい値を超えた場合に更新を防止できる場合があります。それで、少し検索して、誰かがこのスニペットのようにすでにこれに関する記事を書いているのを見つけました
CREATE TRIGGER [Purchasing].[uPreventWholeUpdate]
ON [Purchasing].[VendorContact]
FOR UPDATE AS
BEGIN
DECLARE @Count int
SET @Count = @@ROWCOUNT;
IF @Count >= (SELECT SUM(row_count)
FROM sys.dm_db_partition_stats
WHERE OBJECT_ID = OBJECT_ID('Purchasing.VendorContact' )
AND index_id = 1)
BEGIN
RAISERROR('Cannot update all rows',16,1)
ROLLBACK TRANSACTION
RETURN;
END
END
これは実際には正しい修正ではありませんが、これを適切にログに記録すれば、データを台無しにして修正しようとした原因を突き止めることができると思います。
幸運を祈ります
トランザクション ログ エクスプローラーは、誰が、いつ、どのように具体的にコマンドを実行したかを確認できる必要があります。
どのログ エクスプローラーを使用していますか? ApexSQL ログを使用している場合は、追加のログイン詳細を取得するために、接続監視機能を有効にする必要があります。
This might be like using a sledgehammer to drive in a thumb tack, but have you considered using SQL Server Auditing (provided you are using SQL Server Enterprise 2008 or greater)?