Estamos haciendo un proceso ETL. Cuando todo está dicho y hecho, hay un montón de tablas que deberían ser idénticas. ¿Cuál es la forma más rápida de verificar que esas tablas (en dos servidores diferentes) sean de hecho idénticas? Estoy hablando tanto de esquema como de datos.
¿Puedo hacer un hash en la tabla, como lo haría en un archivo individual o grupo de archivos, para comparar uno con el otro? Tenemos una comparación de datos de Red-Gate, pero dado que las tablas en cuestión contienen millones de filas cada una, me gustaría algo un poco más eficiente.
Un enfoque que me intriga es este uso creativo de la declaración del sindicato . Pero, si es posible, me gustaría explorar un poco más la idea del hash.
PUBLICAR ACTUALIZACIÓN DE RESPUESTA
Para cualquier visitante futuro ... aquí está el enfoque exacto que terminé tomando. Funcionó tan bien que lo estamos haciendo en cada tabla de cada base de datos. Gracias a las respuestas a continuación por señalarme en la dirección correcta.
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
fuente
Respuestas:
Esto es lo que he hecho antes:
Funcionó lo suficientemente bien en tablas que tienen aproximadamente 1,000,000 de filas, pero no estoy seguro de qué tan bien funcionaría en tablas extremadamente grandes.
Adicional:
Ejecuté la consulta en mi sistema, que compara dos tablas con 21 campos de tipos regulares en dos bases de datos diferentes conectadas al mismo servidor que ejecuta SQL Server 2005. La tabla tiene aproximadamente 3 millones de filas y hay alrededor de 25000 filas diferentes. Sin embargo, la clave principal de la tabla es extraña, ya que es una clave compuesta de 10 campos (es una tabla de auditoría).
Los planes de ejecución de las consultas tienen un costo total de 184.25879 para
UNION
y 184.22983 paraUNION ALL
. El costo del árbol solo difiere en el último paso antes de devolver filas, la concatenación.En realidad, ejecutar cualquiera de las consultas toma aproximadamente 42 segundos más 3 segundos para transmitir las filas. El tiempo entre las dos consultas es idéntico.
Segunda adición:
En realidad, esto es extremadamente rápido, cada uno corriendo contra 3 millones de filas en aproximadamente 2.5s:
Si los resultados no coinciden, sabrá que las tablas son diferentes. Sin embargo, si los resultados hacen partido, que está no garantiza que las tablas son idénticos debido a la posibilidad [altamente improbable] de colisiones de suma de comprobación.
No estoy seguro de cómo los cambios de tipo de datos entre tablas afectarían este cálculo. Ejecutaría la consulta contra las
system
vistas oinformation_schema
vistas.Intenté la consulta en otra tabla con 5 millones de filas y esa se ejecutó en aproximadamente 5 segundos, por lo que parece ser en gran medida O (n).
fuente
Aquí hay varias ideas que pueden ayudar:
Pruebe diferentes herramientas de diferencia de datos: ¿ha probado el conjunto de herramientas de comparación SQL de Idera o ApexSQL Data Diff ? Me doy cuenta de que ya pagó por RG, pero aún puede usarlos en modo de prueba para hacer el trabajo;).
Divide y vencerás: ¿qué tal dividir tablas en 10 tablas más pequeñas que pueden ser manejadas por alguna herramienta de comparación de datos comerciales?
Limítese solo a algunas columnas: ¿realmente necesita comparar datos en todas las columnas?
fuente
Creo que deberías investigar BINARY_CHECKSUM, aunque optaría por la herramienta Red Gate:
http://msdn.microsoft.com/en-us/library/ms173784.aspx
Algo como esto:
fuente
Si tiene una clave primaria, esta es a veces una mejor manera de examinar las diferencias porque las filas que deberían ser las mismas se muestran juntas.
Véalo en un sqlfiddle .
fuente