Detectar cambios en los datos en SQL Server

Saber si los datos almacenados en una base de datos han cambiado es un problema al que nos enfrentamos frecuentemente. Son varios los escenarios en los que tenemos esta necesidad:

  • Enviar solo a un cliente desconectado los datos que han cambiado mientras no tenía conexión.
  • Actualizar datos cacheados solo si los datos subyacentes a la caché han cambiado.
  • Refrescar la representación de los datos en una interfaz de usuario compleja solo si estos han cambiado.

Los niveles a los que nos puede interesar detectar cambios en los datos son varios: detectar que los datos de una fila concreta han cambiado, detectar si los datos en una columna determinada de una columna han cambiado o detectar si alguno de los campos de un conjunto de filas (o una tabla completa) han cambiado. Existe una manera muy simple de conseguir esto en SQL Server que no es muy conocida: apoyarse en las funciones de checksum.

El mecanismo es bien simple: si un solo bit de un conjunto de datos cambia, su checksum cambia. Evidentemente es mucho más simple almacenar y comprobar cambios en el checksum de un conjunto de datos que comprobar si alguno de los campos del conjunto de datos ha cambiado.

¿Cómo detectar cambios en una fila?

SELECT BINARY_CHECKSUM(*) FROM [AdventureWorks].[HumanResources].[Department]
WHERE DepartmentID = @DeparmentID

Si nos interesa podemos calcular el checksum de algunos campos.

SELECT BINARY_CHECKSUM(Name, GroupName) FROM [AdventureWorks].[HumanResources].[Department]
WHERE DepartmentID = @DeparmentID

¿Cómo detectar cambios en un conjunto de filas o una tabla completa?

Aquí el truco es saber que en SQL Server contamos con una función de agregación que nos permite calcular el checksum. Así que primero calculamos el checksum de la fila y luego el checksum agregado del checksum de cada

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM [AdventureWorks].[HumanResources].[Department]

Evidentemente podemos filtrar los datos que nos interesa con una clausula WHERE para limitar el conjunto de filas.

¿Cómo detectar cambios en una columna concreta?

La técnica es similar a la anterior.

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(Name)) FROM [AdventureWorks].[HumanResources].[Department]

¿Y el rendimiento?

Pues en el caso más desfavorable tendremos un ‘full scan’, pero este caso solo se da si calculamos el checksum de una tabla completa que no cuente con un índice clustered. En caso de contar con un indicé clustered, tendremos un ‘index scan’. Es importante desde el punto de vista del rendimiento, en el caso de detectar cambios en una columna concreta, es importante que está cuente con un índice.

Podéis ver los planes de ejecución en la siguiente imagen:

Planes de ejecución

La conclusión es que con índices adecuados el rendimiento de esta solución es al menos tan buena como con cualquier otra. Al final si quieres saber si los datos han cambiado nadie te va a librar de leerlos.

¡Espero que os sea útil!

Published 31/8/2011 23:59 por Rodrigo Corral
Comparte este post:
http://geeks.ms/blogs/rcorral/archive/2011/08/31/detectar-cambios-en-los-datos-en-sql-server.aspx

Comentarios

# re: Detectar cambios en los datos en SQL Server

Otra aproximación, muy diferente, pero que en ciertos escenarios puede funcionar bien es utilizar SqlDependency.

Un saludo.

Thursday, September 1, 2011 9:39 AM por Juan Irigoyen

# re: Detectar cambios en los datos en SQL Server

Cierto Juan, SqlDependency es otra opción y usar campos de tipo row_version (el anteriormente TimeSpam ahora obsoleto) otra. Según el escenario concreto puede interesar más una u otra aproximación.

Gracias por el apunte.

Thursday, September 1, 2011 12:37 PM por Rodrigo Corral

# re: Detectar cambios en los datos en SQL Server

Me apuntan por twitter una opción más:

SQL Server Change Data Capture

msdn.microsoft.com/.../cc645937.aspx

Puede ser una opción valida en varios escenarios. Pero es artillería pesada, no es tan simple como lo comentado en el blog y también es mucho más potente.

Un saludo.

Friday, September 2, 2011 12:52 PM por Rodrigo Corral