วิธีที่รวดเร็วในการตรวจสอบสองตารางกับแต่ละอื่น ๆ


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

คำตอบ:


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 ตารางมีประมาณ 3 ล้านแถวและมีประมาณ 25,000 แถวที่แตกต่างกัน คีย์หลักบนโต๊ะแปลก แต่เป็นคีย์ผสมของ 10 ฟิลด์ (เป็นตารางตรวจสอบ)

แผนการดำเนินการสำหรับการค้นหามีค่าใช้จ่ายทั้งหมดของ 184.25879 สำหรับUNIONและ 184.22983 UNION ALLสำหรับ ค่าใช้จ่ายของต้นไม้จะแตกต่างกันไปในขั้นตอนสุดท้ายก่อนที่จะส่งคืนแถว, การต่อข้อมูล

การดำเนินการแบบสอบถามจริง ๆ แล้วใช้เวลาประมาณ 42 วินาทีและประมาณ 3 วินาทีเพื่อส่งแถวจริง ๆ เวลาระหว่างแบบสอบถามทั้งสองจะเหมือนกัน

การเพิ่มครั้งที่สอง:

อันนี้เร็วมากจริง ๆ แล้วแต่ละอันวิ่งกับ 3 ล้านแถวในเวลาประมาณ 2.5 วินาที:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableA

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableB

หากผลลัพธ์ของสิ่งเหล่านั้นไม่ตรงกันคุณรู้ว่าตารางนั้นแตกต่างกัน แต่ถ้าผลที่ได้ทำตรงกับที่คุณไม่ได้รับประกันว่าตารางเหมือนกันเพราะ [ไม่น่าจะสูง] โอกาสของการตรวจสอบการชนกัน

ฉันไม่แน่ใจว่าการเปลี่ยนแปลงประเภทข้อมูลระหว่างตารางจะมีผลต่อการคำนวณนี้อย่างไร ฉันจะเรียกใช้แบบสอบถามกับsystemมุมมองหรือinformation_schemaมุมมอง

ฉันลองค้นหากับตารางอื่นที่มี 5 ล้านแถวและอันนั้นวิ่งไปประมาณ 5 วินาทีดังนั้นจึงดูเหมือนว่า O (n) ส่วนใหญ่


8

นี่คือแนวคิดหลายประการที่อาจช่วยได้:

  1. ลองใช้เครื่องมือข้อมูลต่างที่แตกต่างกัน - มีคุณพยายาม Idera ของชุดเครื่องมือเปรียบเทียบ SQLหรือApexSQL Diff ฉันรู้ว่าคุณจ่ายให้ 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(*))ระหว่างสองตารางที่เหมือนกันที่มีการตรวจสอบการจับคู่ หลังจากที่ฉันเพิ่มคอลัมน์ในหนึ่งในตารางแล้วค่าการตรวจสอบก็ไม่เหมือนกันอีกต่อไป
Jeff Mergler

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.