İki tabloyu birbirine göre doğrulamanın hızlı yolu


13

ETL süreci yapıyoruz. Her şey söylendiğinde ve yapıldığında, aynı olması gereken bir sürü tablo var. Bu tabloların (iki farklı sunucuda) aslında aynı olduğunu doğrulamanın en hızlı yolu nedir? Hem şemadan hem de veriden söz ediyorum.

Tabloda bir karma yapabilir miyim, tek tek bir dosya veya dosya grubunda yapabileceğim gibi - diğerini karşılaştırmak için. Red-Gate verilerinin karşılaştırılması var, ancak söz konusu tablolarda milyonlarca satır bulunduğundan, her biri biraz daha performanslı bir şey istiyorum.

Beni ilgilendiren bir yaklaşım , sendika ifadesinin bu yaratıcı kullanımıdır . Ancak, mümkünse karma fikri biraz daha araştırmak istiyorum.

YANIT SONRASI GÜNCELLEME

Gelecekteki tüm izleyiciler için ... işte benim yaklaştığım kesin yaklaşım. Her veritabanındaki her masada yapıyoruz o kadar iyi çalıştı. Beni doğru yöne yönlendiren aşağıdaki cevaplar için teşekkürler.

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 bir seçenek midir? Bir tabloda okumak ve diğerine karşı arama yapmak oldukça kolay olurdu.
Kevin

1
Bu bir seçenektir, ETL süreci için kullanılan şeydir, ancak üst kattaki bıyıklar, SSIS'in doğru olduğunu kanıtlamak için SSIS kullanmanın işe yarayıp yaramadığı konusunda ikinci bir görüş ister veya CheckSum veya MD5 Karma.
RThomas

Yanıtlar:


18

Daha önce yaptığım şey:

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

Yaklaşık 1.000.000 satır olan tablolarda yeterince çalıştı, ancak bunun çok büyük tablolarda ne kadar iyi çalışacağından emin değilim.

Katma:

SQL Server 2005 çalıştıran aynı sunucuya bağlı iki farklı veritabanında iki farklı türde 21 tablo ile iki tablo karşılaştıran sistemime karşı sorgu çalıştırdım. Tablo yaklaşık 3 milyon satır var ve yaklaşık 25000 satır farklı. Bununla birlikte, tablodaki birincil anahtar gariptir, çünkü 10 alanın birleşik anahtarıdır (bir denetim tablosu).

Sorguların yürütme planlarının toplam maliyeti 184.25879 UNIONve için 184.22983'tür UNION ALL. Ağaç maliyeti yalnızca satırları (birleştirme) döndürmeden önceki son adımda farklılık gösterir.

Aslında her iki sorguyu yürütmek, satırları iletmek için yaklaşık 42 saniye artı yaklaşık 3 saniye sürer. İki sorgu arasındaki süre aynıdır.

İkinci Ek:

Bu aslında son derece hızlı, her biri yaklaşık 2,5 saniyede 3 milyon sıraya karşı çalışıyor:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableA

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM TableB

Bunların sonuçları uyuşmuyorsa, tabloların farklı olduğunu bilirsiniz. Sonuçlar Ancak, do maçı, sen ettiğin değil tabloları nedeniyle sağlama çarpışmaların [pek olası] Şans aynı olduğunu garanti.

Tablolar arasındaki veri türü değişikliklerinin bu hesaplamayı nasıl etkileyeceğinden emin değilim. Ben systemgörünümler veya information_schemagörünümler karşı sorgu çalıştırmak .

Ben 5 milyon satır ile başka bir tabloya karşı sorgu denedim ve biri yaklaşık 5s koştu, bu yüzden büyük ölçüde O (n) gibi görünüyor.


8

İşte size yardımcı olabilecek birkaç fikir:

  1. Farklı veri farkı aracını deneyin - Idera'nın SQL Karşılaştırma araç setini veya ApexSQL Data Diff'i denediniz mi ? Zaten RG için ödeme yaptığınızın farkındayım, ancak yine de bu işi yapmak için deneme modunda kullanabilirsiniz;).

  2. Böl ve fethet - tabloları bazı ticari veri karşılaştırma aracıyla işlenebilecek 10 küçük tabloya bölmeye ne dersiniz?

  3. Kendinizi yalnızca bazı sütunlarla sınırlandırın - gerçekten tüm sütunlardaki verileri karşılaştırmanız mı gerekiyor?


7

Red Gate aracını tercih etsem de, BINARY_CHECKSUM'u araştırmanız gerektiğine inanıyorum:

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

Bunun gibi bir şey:

SELECT BINARY_CHECKSUM(*) from myTable;

Bu, tabloların şemasındaki farklılıkları (farklı sütun adları veya veri türleri) algılar mı?
ypercubeᵀᴹ

@ ypercubeᵀᴹ evet, bunu onaylayabilirim. CHECKSUM_AGG(BINARY_CHECKSUM(*))Sağlama toplamlarının eşleştiği iki özdeş tablo arasında kullanımını test ediyordum . Tablolardan birine bir sütun ekledikten sonra sağlama toplamı değerleri artık aynı değildi.
Jeff Mergler

3

Birincil anahtarınız varsa, bu bazen farklılıkları incelemenin daha iyi bir yoludur, çünkü aynı olması gereken satırlar birlikte gösterilir.

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

Bunu bir sqlfiddle'da görün .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.