Modo rapido per convalidare due tabelle l'una contro l'altra


12

Stiamo facendo un processo ETL. Quando tutto è detto e fatto ci sono un sacco di tabelle che dovrebbero essere identiche. Qual è il modo più rapido per verificare che quelle tabelle (su due server diversi) siano effettivamente identiche. Sto parlando sia di schema che di dati.

Posso fare un hash sul tavolo è come se fossi su un singolo file o filegroup - per confrontare l'uno con l'altro. Abbiamo confrontato i dati di Red-Gate ma dato che le tabelle in questione contengono milioni di righe ognuna, vorrei qualcosa di un po 'più performante.

Un approccio che mi incuriosisce è questo uso creativo della dichiarazione sindacale . Ma mi piacerebbe esplorare l'idea dell'hash un po 'più lontano, se possibile.

AGGIORNAMENTO RISPOSTA POST

Per eventuali futuri visitatori ... ecco l'approccio esatto che ho finito per seguire. Ha funzionato così bene che lo stiamo facendo su ogni tabella di ogni database. Grazie alle risposte di seguito per avermi indicato nella giusta direzione.

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 è un'opzione? Sarebbe abbastanza facile da leggere in una tabella e fare una ricerca sull'altra.
Kevin

1
È un'opzione, è ciò che viene utilizzato per il processo ETL, ma i baffi al piano di sopra vogliono un secondo parere su se ha funzionato o meno utilizzando SSIS per dimostrare che SSIS ha capito bene non è così convincente come far cadere parole fantasiose come CheckSum o Hash MD5.
RThomas

Risposte:


17

Ecco cosa ho fatto prima:

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

Ha funzionato abbastanza bene su tabelle che sono circa 1.000.000 di righe, ma non sono sicuro di come funzionerebbe su tabelle estremamente grandi.

Inserito il:

Ho eseguito la query sul mio sistema che confronta due tabelle con 21 campi di tipo normale in due diversi database collegati allo stesso server che esegue SQL Server 2005. La tabella ha circa 3 milioni di righe e circa 25000 righe diverse. La chiave primaria nella tabella è strana, tuttavia, poiché è una chiave composita di 10 campi (è una tabella di controllo).

I piani di esecuzione per le query hanno un costo totale di 184.25879 per UNIONe 184.22983 per UNION ALL. Il costo dell'albero differisce solo nell'ultimo passaggio prima di restituire le righe, la concatenazione.

L'esecuzione effettiva di entrambe le query richiede circa 42 secondi più circa 3 secondi per trasmettere effettivamente le righe. Il tempo tra le due query è identico.

Seconda aggiunta:

Questo è in realtà estremamente veloce, ognuno in esecuzione su 3 milioni di righe in circa 2,5 secondi:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableA

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableB

Se i risultati di questi non corrispondono, sai che le tabelle sono diverse. Tuttavia, se i risultati fanno incontro, si sta non garantito che le tabelle sono identiche a causa del [altamente improbabile] possibilità di collisioni di checksum.

Non sono sicuro di come il cambiamento del tipo di dati tra le tabelle influenzerebbe questo calcolo. Vorrei eseguire la query in base alle systemvisualizzazioni o alle information_schemavisualizzazioni.

Ho provato la query su un'altra tabella con 5 milioni di righe e quella è stata eseguita in circa 5 secondi, quindi sembra essere in gran parte O (n).


8

Ecco alcune idee che potrebbero aiutare:

  1. Prova diversi strumenti per la diffusione dei dati: hai provato il set di strumenti SQL Comparison di Idera o ApexSQL Data Diff . Mi rendo conto che hai già pagato per RG ma puoi comunque usarli in modalità di prova per completare il lavoro;).

  2. Dividi e conquista: che ne dici di dividere le tabelle in 10 tabelle più piccole che possono essere gestite da alcuni strumenti di confronto dei dati commerciali?

  3. Limitati solo ad alcune colonne: hai davvero bisogno di confrontare i dati in tutte le colonne?



3

Se si dispone di una chiave primaria, a volte questo è un modo migliore per esaminare le differenze perché le righe che dovrebbero essere le stesse sono mostrate insieme.

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.*
   );

Vedilo in un sqlfiddle .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.