web-dev-qa-db-ja.com

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

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

個々のファイルまたはファイルグループに対して実行できるように、テーブルに対してハッシュを実行できますか。一方をもう一方と比較できます。 Red-Gateのデータを比較していますが、問題のテーブルには数百万行が含まれているため、もう少しパフォーマンスを向上させたいと考えています。

私の興味をそそる1つのアプローチは このunionステートメントの創造的な使用 です。しかし、可能であればハッシュのアイデアをもう少し詳しく調べたいと思います。

回答後の更新

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

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
14
RThomas

これが私が以前にやったことです:

(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つのテーブルを比較するシステムに対してクエリを実行しました。テーブルには約300万行があり、約25000行が異なります。ただし、テーブルの主キーは10フィールドの複合キーであるため、奇妙です(監査テーブルです)。

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

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

2番目の追加:

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

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableA

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableB

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

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

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

19
Bacon Bits

ここに役立つかもしれないいくつかのアイデアがあります:

  1. 別のデータ差分ツールを試してください-Ideraの SQL比較ツールセット または ApexSQL Data Diff を試しましたか?あなたはすでにRGの支払いを済ませていると思いますが、これらを試用モードで使用して仕事を完了することができます;).

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

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

8
Mark Davidson

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

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

このようなもの:

SELECT BINARY_CHECKSUM(*) from myTable;
7

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

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で確認してください

3
ErikE