Nous faisons un processus ETL. En fin de compte, il y a un tas de tableaux qui devraient être identiques. Quelle est la manière la plus rapide de vérifier que ces tables (sur deux serveurs différents) sont bien identiques. Je parle à la fois de schéma et de données.
Puis-je faire un hachage sur la table, c'est comme si je pouvais le faire sur un fichier individuel ou un groupe de fichiers - pour comparer l'un à l'autre. Nous avons des données Red-Gate à comparer, mais comme les tables en question contiennent chacune des millions de lignes, j'aimerais quelque chose d'un peu plus performant.
Une approche qui m'intrigue est cette utilisation créative de la déclaration syndicale . Mais, j'aimerais explorer l'idée de hachage un peu plus loin si possible.
MISE À JOUR APRÈS RÉPONSE
Pour tous les futurs visiteurs ... voici l'approche exacte que j'ai fini par adopter. Cela a si bien fonctionné que nous le faisons sur chaque table de chaque base de données. Merci aux réponses ci-dessous pour m'avoir pointé dans la bonne direction.
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
la source
Réponses:
Voici ce que j'ai fait auparavant:
Cela a assez bien fonctionné sur des tables d'environ 1 000 000 de lignes, mais je ne sais pas dans quelle mesure cela fonctionnerait sur des tables extrêmement grandes.
Ajoutée:
J'ai exécuté la requête sur mon système qui compare deux tables avec 21 champs de types réguliers dans deux bases de données différentes attachées au même serveur exécutant SQL Server 2005. La table a environ 3 millions de lignes et il y a environ 25 000 lignes différentes. La clé primaire sur la table est cependant étrange, car c'est une clé composite de 10 champs (c'est une table d'audit).
Les plans d'exécution des requêtes ont un coût total de 184.25879 pour
UNION
et 184.22983 pourUNION ALL
. Le coût de l'arbre ne diffère que lors de la dernière étape avant le retour des lignes, la concaténation.L'exécution de l'une ou l'autre requête prend environ 42 secondes et environ 3 secondes pour transmettre les lignes. Le temps entre les deux requêtes est identique.
Deuxième ajout:
C'est en fait extrêmement rapide, chacun fonctionnant contre 3 millions de lignes en environ 2,5 secondes:
Si les résultats de ceux-ci ne correspondent pas, vous savez que les tableaux sont différents. Toutefois, si les résultats font match, vous n'êtes pas garanti que les tables sont identiques en raison de la chance [hautement improbable] des collisions de contrôle.
Je ne sais pas comment les changements de type de données entre les tables affecteront ce calcul. Je voudrais exécuter la requête sur les
system
vues ou lesinformation_schema
vues.J'ai essayé la requête contre une autre table avec 5 millions de lignes et celle-ci a fonctionné en environ 5 s, il semble donc être largement O (n).
la source
Voici plusieurs idées qui pourraient vous aider:
Essayez différents outils de diff de données - avez-vous essayé le jeu d'outils Comparaison SQL d'Idera ou ApexSQL Data Diff . Je me rends compte que vous avez déjà payé RG mais vous pouvez toujours les utiliser en mode d'essai pour faire le travail;).
Diviser pour mieux régner - que diriez-vous de diviser des tables en 10 tables plus petites qui peuvent être gérées par un outil de comparaison de données commercial?
Limitez-vous uniquement à certaines colonnes - avez-vous vraiment besoin de comparer les données de toutes les colonnes?
la source
Je pense que vous devriez enquêter sur BINARY_CHECKSUM, bien que j'opterais pour l'outil Red Gate:
http://msdn.microsoft.com/en-us/library/ms173784.aspx
Quelque chose comme ça:
la source
Si vous avez une clé primaire, c'est parfois une meilleure façon d'examiner les différences car les lignes qui doivent être identiques sont affichées ensemble.
Voyez-le dans un sqlfiddle .
la source