checksum_agg は、binary_checksum の結果をすべての行に対して単純に加算しているように見えます。各行は変更されていますが、2 つのチェックサムの合計は変更されていません (つまり、17+32 = 16+33)。これは実際には更新を確認するための標準ではありませんが、私が思いつく推奨事項は次のとおりです。
- を使用する代わりに
checksum_agg
、チェックサムを区切られた文字列に連結し、文字列を比較しますSELECT binary_checksum(*) + ',' FROM MyTable FOR XML PATH('')
。チェックして保存する文字列ははるかに長くなりますが、誤検出の可能性ははるかに低くなります。
- 組み込みのチェックサム ルーチンを使用する代わりに、HASHBYTES を使用して 8000 バイト ブロックで MD5 チェックサムを計算し、結果を xor します。これにより、チェックサムの弾力性が大幅に向上しますが、完全な防御ではありません (つまり、誤った一致が得られる可能性はありますが、その可能性は非常に低くなります)。以下に書いた HASHBYTES デモコードを貼り付けます。
- 最後のオプションであり、絶対的な最後の手段は、実際にテーブル table を XML 形式で保存し、それを比較することです。これは、誤った一致がないことを完全に確認できる唯一の方法ですが、スケーラブルではなく、大量のデータを保存して比較する必要があります。
あなたが始めたものを含め、すべてのアプローチには長所と短所があり、さまざまな程度のデータサイズと精度に対する処理要件があります。必要な精度のレベルに応じて、適切なオプションを使用してください。100% の精度を得る唯一の方法は、すべてのテーブル データを保存することです。
別の方法として、各テーブルに date_modified フィールドを追加することもできます。このフィールドは、after insert および update トリガーを使用して GetDate() に設定されます。できますSELECT COUNT(*) FROM #test WHERE date_modified > @date_last_checked
。これは、更新を確認するためのより一般的な方法です。これの欠点は、削除を追跡できないことです。
もう 1 つの方法は、追跡するテーブルごとに 1 つの行を含む、table_name (VARCHAR) フィールドと is_modified (BIT) フィールドを使用して、変更されたテーブルを作成することです。挿入、更新、および削除のトリガーを使用して、関連するテーブルに対するフラグを True に設定します。スケジュールを実行するときは、(同じトランザクションで) is_modified フラグを確認してリセットします - 次の行に沿ってSELECT @is_modified = is_modified, is_modified = 0 FROM tblModified
次のスクリプトは、3 つの結果セットを生成します。それぞれが、この応答で前述した番号付きリストに対応しています。SELECT ステートメントの直前に、どの出力がどのオプションに対応するかをコメントしました。出力がどのように導出されたかを確認するには、コードをさかのぼって作業します。
-- Create the test table and populate it
CREATE TABLE #Test (
f1 INT,
f2 INT
)
INSERT INTO #Test VALUES(1, 1)
INSERT INTO #Test VALUES(2, 0)
INSERT INTO #Test VALUES(2, 1)
/*******************
OPTION 1
*******************/
SELECT CAST(binary_checksum(*) AS VARCHAR) + ',' FROM #test FOR XML PATH('')
-- Declaration: Input and output MD5 checksums (@in and @out), input string (@input), and counter (@i)
DECLARE @in VARBINARY(16), @out VARBINARY(16), @input VARCHAR(MAX), @i INT
-- Initialize @input string as the XML dump of the table
-- Use this as your comparison string if you choose to not use the MD5 checksum
SET @input = (SELECT * FROM #Test FOR XML RAW)
/*******************
OPTION 3
*******************/
SELECT @input
-- Initialise counter and output MD5.
SET @i = 1
SET @out = 0x00000000000000000000000000000000
WHILE @i <= LEN(@input)
BEGIN
-- calculate MD5 for this batch
SET @in = HASHBYTES('MD5', SUBSTRING(@input, @i, CASE WHEN LEN(@input) - @i > 8000 THEN 8000 ELSE LEN(@input) - @i END))
-- xor the results with the output
SET @out = CAST(CAST(SUBSTRING(@in, 1, 4) AS INT) ^ CAST(SUBSTRING(@out, 1, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 5, 4) AS INT) ^ CAST(SUBSTRING(@out, 5, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 9, 4) AS INT) ^ CAST(SUBSTRING(@out, 9, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 13, 4) AS INT) ^ CAST(SUBSTRING(@out, 13, 4) AS INT) AS VARBINARY(4))
SET @i = @i + 8000
END
/*******************
OPTION 2
*******************/
SELECT @out