Швидкий спосіб перевірити дві таблиці один проти одного


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

Відповіді:


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 мільйонів рядків, а приблизно 25000 рядків. Однак первинний ключ у таблиці дивний, оскільки це складовий ключ з 10 полів (це таблиця аудиту).

Плани виконання запитів мають загальну вартість 184,25879 для UNIONта 184,22983 для UNION ALL. Вартість дерева відрізняється лише на останньому кроці перед поверненням рядків, конкатенації.

Насправді виконання будь-якого запиту займає приблизно 42s плюс близько 3s, щоб фактично передавати рядки. Час між двома запитами однаковий.

Друге доповнення:

Це насправді надзвичайно швидко, кожен працює проти 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. Спробуйте інший інструмент різниці даних - чи спробували ви набір інструментів для порівняння SQL Idera або ApexSQL Data 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(*))між двома однаковими таблицями, де збігалися контрольні суми. Після того, як я додав стовпчик до однієї з таблиць, значення контрольної суми більше не були ідентичними.
Джефф Мерглер

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 .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.