相互验证两个表的快速方法


13

我们正在执行ETL流程。说完所有的话,有一堆表应该是相同的。验证那些表(在两个不同服务器上)实际上是否相同的最快方法是什么。我在说模式和数据。

我可以像在单个文件或文件组上一样对表进行哈希运算吗?可以相互比较。我们有Red-Gate数据比较,但是由于有问题的表包含数百万行,因此我希望每个表都具有更高的性能。

一种吸引我的方法是对联合声明的创造性使用。但是,如果可能的话,我想进一步探讨一下哈希概念。

发布答复更新

对于任何未来的参观者……这就是我最终采取的确切方法。效果很好,我们正在每个数据库中的每个表上执行此操作。感谢下面的回答为我指出了正确的方向。

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
这是一个选择,这是ETL流程所使用的,但是楼上的胡须要对它是否起作用提出第二个意见,因此使用SSIS来证明SSIS正确无误地不如丢掉CheckSum或MD5哈希。
RThomas

Answers:


18

这是我之前所做的:

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

在大约1,000,000行的表上,它已经足够好了,但是我不确定这在超大表上的表现如何。

添加:

我已经对我的系统运行了查询,该系统将两个表与21个常规类型的字段进行比较,这些表具有连接到运行SQL Server 2005的同一服务器的两个不同数据库中的常规类型。该表大约有300万行,大约有25000行。该表上的主键很奇怪,因为它是10个字段的组合键(这是一个审计表)。

这些查询的执行计划的总成本为184.25879 UNION和184.22983 UNION ALL。树成本仅在返回行(串联)之前的最后一步有所不同。

实际执行任一查询大约需要42s加3s才能实际传输行。两个查询之间的时间是相同的。

第二增加:

这实际上是非常快的,每一个大约在2.5秒内运行300万行:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableA

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableB

如果这些结果不匹配,则说明表是不同的。但是,如果结果确实匹配,则由于[校验和冲突的可能性极小],因此不能保证这些表相同。

我不确定表之间的数据类型更改如何影响此计算。我将针对system视图或information_schema视图运行查询。

我尝试对另一个具有500万行的表进行查询,该表的运行时间约为5s,因此看起来大部分都是O(n)。


8

这里有一些想法可能会有所帮助:

  1. 尝试使用其他数据差异工具-您是否尝试过使用Idera的SQL比较工具集ApexSQL数据差异。我知道您已经为RG付款,但是您仍然可以在试用模式下使用它们来完成工作;)。

  2. 分而治之-如何将表格分为10个较小的表格,可以由某些商业数据比较工具处理?

  3. 仅将自己限制在某些列中-您是否真的需要比较所有列中的数据?


7

我相信您应该调查BINARY_CHECKSUM,尽管我会选择Red Gate工具:

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

像这样:

SELECT BINARY_CHECKSUM(*) from myTable;

这样是否可以检测到表架构中的差异(不同的列名或数据类型)?
ypercubeᵀᴹ

@ypercubeᵀᴹ是的,我可以确认这一点。我正在测试CHECKSUM_AGG(BINARY_CHECKSUM(*))校验和匹配的两个相同表之间的使用。在向其中一个表中添加一列后,校验和值不再相同。
杰夫·梅格勒

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中看到它

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.