2つのテーブルを相互に検証する簡単な方法


12

ETLプロセスを行っています。すべてを言い終えると、同一のテーブルがたくさんあります。(2つの異なるサーバー上の)それらのテーブルが実際に同一であることを確認する最も簡単な方法は何ですか。私はスキーマとデータの両方を話しています。

個々のファイルまたはファイルグループでできるように、テーブルでハッシュを実行できますか?Red-Gateのデータ比較がありますが、問題のテーブルにはそれぞれ数百万の行が含まれているため、もう少しパフォーマンスの高いものが欲しいです。

私の興味を引く1つのアプローチは、組合声明のこの創造的な使用です。しかし、可能であれば、ハッシュのアイデアをもう少し詳しく調べたいと思います。

回答の更新後

将来の訪問者のために...ここに私が取った正確なアプローチがあります。これは非常にうまく機能し、各データベースのすべてのテーブルで実行しています。私を正しい方向に向けてくれた以下の回答に感謝します。

CREATE PROCEDURE [dbo].[usp_DatabaseValidation]
    @TableName varchar(50)

AS
BEGIN

    SET NOCOUNT ON;

    -- parameter = if no table name was passed do them all, otherwise just check the one

    -- create a temp table that lists all tables in target database

    CREATE TABLE #ChkSumTargetTables ([fullname] varchar(250), [name] varchar(50), chksum int);
    INSERT INTO #ChkSumTargetTables ([fullname], [name], [chksum])
        SELECT DISTINCT
            '[MyDatabase].[' + S.name + '].['
            + T.name + ']' AS [fullname],
            T.name AS [name],
            0 AS [chksum]
        FROM MyDatabase.sys.tables T
            INNER JOIN MyDatabase.sys.schemas S ON T.schema_id = S.schema_id
        WHERE 
            T.name like IsNull(@TableName,'%');

    -- create a temp table that lists all tables in source database

    CREATE TABLE #ChkSumSourceTables ([fullname] varchar(250), [name] varchar(50), chksum int)
    INSERT INTO #ChkSumSourceTables ([fullname], [name], [chksum])
        SELECT DISTINCT
            '[MyLinkedServer].[MyDatabase].[' + S.name + '].['
            + T.name + ']' AS [fullname],
            T.name AS [name],
            0 AS [chksum]
        FROM [MyLinkedServer].[MyDatabase].sys.tables T
            INNER JOIN [MyLinkedServer].[MyDatabase].sys.schemas S ON 
            T.schema_id = S.schema_id
        WHERE
            T.name like IsNull(@TableName,'%');;

    -- build a dynamic sql statement to populate temp tables with the checksums of each table

    DECLARE @TargetStmt VARCHAR(MAX)
    SELECT  @TargetStmt = COALESCE(@TargetStmt + ';', '')
            + 'UPDATE #ChkSumTargetTables SET [chksum] = (SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM '
            + T.FullName + ') WHERE [name] = ''' + T.Name + ''''
    FROM    #ChkSumTargetTables T

    SELECT  @TargetStmt

    DECLARE @SourceStmt VARCHAR(MAX)
    SELECT  @SourceStmt = COALESCE(@SourceStmt + ';', '')
            + 'UPDATE #ChkSumSourceTables SET [chksum] = (SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM '
            + S.FullName + ') WHERE [name] = ''' + S.Name + ''''
    FROM    #ChkSumSourceTables S

    -- execute dynamic statements - populate temp tables with checksums

    EXEC (@TargetStmt);
    EXEC (@SourceStmt);

    --compare the two databases to find any checksums that are different

    SELECT  TT.FullName AS [TABLES WHOSE CHECKSUM DOES NOT MATCH]
    FROM #ChkSumTargetTables TT
    LEFT JOIN #ChkSumSourceTables ST ON TT.Name = ST.Name
    WHERE IsNull(ST.chksum,0) <> IsNull(TT.chksum,0)

    --drop the temp tables from the tempdb

    DROP TABLE #ChkSumTargetTables;
    DROP TABLE #ChkSumSourceTables;

END

SSISはオプションですか?1つのテーブルを読み取り、他のテーブルを検索するのはかなり簡単です。
ケビン

1
それはオプションであり、ETLプロセスに使用されているものですが、2階の口ひげはそれが機能したかどうかについてセカンドオピニオンを望んでいます。 MD5ハッシュ。
–RThomas

回答:


17

以前にやったことは次のとおりです。

(SELECT 'TableA', * FROM TableA
EXCEPT
SELECT 'TableA', * FROM TableB)
UNION ALL
(SELECT 'TableB', * FROM TableB
EXCEPT
SELECT 'TableB', * FROM TableA)

約1,000,000行のテーブルでは十分に機能しましたが、非常に大きなテーブルでどの程度うまく機能するかはわかりません。

追加:

SQL Server 2005を実行している同じサーバーに接続された2つの異なるデータベースの21種類の通常のフィールドを持つ2つのテーブルを比較するシステムに対してクエリを実行しました。ただし、10個のフィールドからなる複合キー(監査テーブル)であるため、テーブルの主キーは奇妙です。

クエリの実行プランの合計コストは184.25879でUNION1844.22983ですUNION ALL。ツリーのコストは、行を返す前の最後のステップ、つまり連結でのみ異なります。

実際にいずれかのクエリを実行するには、実際に行を送信するのに約42秒と約3秒かかります。2つのクエリ間の時間は同じです。

2番目の追加:

これは実際には非常に高速で、それぞれが約2.5秒で300万行に対して実行されます。

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableA

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableB

それらの結果が一致しない場合、テーブルが異なることがわかります。ただし、結果一致する場合、チェックサムの衝突の可能性が非常に低いため、テーブルが同一であることは保証されません。

テーブル間のデータ型の変更がこの計算にどのように影響するかわかりません。systemビューまたはinformation_schemaビューに対してクエリを実行します。

500万行の別のテーブルに対してクエリを実行したところ、約5秒で実行されたため、ほとんどがO(n)のようです。


1
UNION ALLではなくUNIONを提案するのはなぜですか?どの重複を排除しますか?
AK

@AlexKuznetsovまあまあですが、クエリエンジンは主キー全体を選択していることを認識できるほどスマートであるか、EXCEPTステートメントから結果セットが得られるまで個別を処理しない可能性があります。もしそうなら今私は実際に興味があります。ただし、RDBMSに明示的にする方が論理的ですので、更新します。
ベーコンビット

ただし、質問は2つの異なるサーバーについてです。
ypercubeᵀᴹ

テストするサーバーが2つありません。:)
ベーコンビット

リンクサーバーアプローチ全体の連合では、心配していました。私は集約とbinary_checksumのアプローチが好きです...それでいくつかのテストを始めます。
–RThomas

8

以下に役立ついくつかのアイデアを示します。

  1. 別のデータ差分ツールを試してください-IderaSQL比較ツールセットまたはApexSQLデータ差分を試しましたか。私はあなたがすでにRGの支払いをしていることを理解していますが、あなたはまだこれらを試用モードで使用して仕事を終わらせることができます;)。

  2. 分割して征服する-いくつかの商用データ比較ツールで処理できる10個の小さなテーブルにテーブルを分割するのはどうですか?

  3. 一部の列のみに制限する-すべての列のデータを本当に比較する必要がありますか?


7

Red Gateツールを選択しますが、BINARY_CHECKSUMを調査する必要があると思います。

http://msdn.microsoft.com/en-us/library/ms173784.aspx

このようなもの:

SELECT BINARY_CHECKSUM(*) from myTable;

これにより、テーブルのスキーマの違い(異なる列名またはデータ型)が検出されますか?
ypercubeᵀᴹ

これには可能性があります。いくつかのテストを行ってから戻ります。
–RThomas

プラス1を与えましたが、ベーコンビットによって提供される集合体が一番上のアイシングでした。ありがとう。
–RThomas

3

主キーがある場合、これは、同じであるはずの行が一緒に表示されるため、違いを調べるためのより良い方法です。

SELECT
   ID = IsNull(A.ID, B.ID),
   AValue = A.Value,
   BValue = B.Value
FROM
   dbo.TableA A
   FULL JOIN dbo.TableB B
      ON A.ID = B.ID
WHERE
   EXISTS (
      SELECT A.*
      EXCEPT SELECT B.*
   );

sqlfiddleで参照してください


ニース、ありがとう...集計が違いの存在を示した後に違いを見つける良い方法です。ありがとう。
–RThomas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.