¿Buscar cambios en una tabla de SQL Server?


¿Cómo puedo monitorear una base de datos SQL Server para ver si hay cambios en una tabla sin usar disparadores o modificar la estructura de la base de datos de ninguna manera? Mi entorno de programación preferido es . NET y C#.

Me gustaría ser capaz de soportar cualquier SQL Server 2000 SP4 o posterior. Mi aplicación es una visualización de datos atornillada para el producto de otra empresa. Nuestra base de clientes está en los miles, por lo que no quiero tener que poner en los requisitos que modificamos el tercero mesa del proveedor en cada instalación.

Por "cambios en una tabla" Me refiero a los cambios en los datos de la tabla, no a los cambios en la estructura de la tabla.

En última instancia, me gustaría que el cambio desencadenara un evento en mi aplicación, en lugar de tener que verificar los cambios en un intervalo.


El mejor curso de acción dados mis requisitos (sin disparadores o modificación del esquema, SQL Server 2000 y 2005) parece ser usar la función BINARY_CHECKSUM en T-SQL. La forma en que planeo implementar es esto:

Cada X segundos ejecute la siguiente consulta:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))
FROM sample_table
WITH (NOLOCK);

Y compare eso con el valor almacenado. Si el valor ha cambiado, vaya a través de la tabla fila por fila usando la consulta:

SELECT row_id, BINARY_CHECKSUM(*)
FROM sample_table
WITH (NOLOCK);

Y compare las sumas de comprobación devueltas con los valores almacenados.

Author: Nhan, 2008-08-01

8 answers

Echa un vistazo al comando CHECKSUM:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);

Eso devolverá el mismo número cada vez que se ejecute siempre y cuando el contenido de la tabla no haya cambiado. Ver mi post sobre esto para más información:

SUMA DE COMPROBACIÓN

Así es como lo usé para reconstruir las dependencias de caché cuando las tablas cambiaban:
ASP.NET 1.1 dependencia de caché de base de datos (sin disparadores)

 93
Author: Jon Galloway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-28 03:44:42

Desafortunadamente CHECKSUM no siempre funciona correctamente para detectar cambios. Es solo una suma de comprobación primitiva y ningún cálculo CRC. Por lo tanto, no se puede utilizar para detectar todos los cambios, por ejemplo, los cambios simétricos resultan en la misma SUMA de comprobación!

Por ejemplo, la solución con CHECKSUM_AGG(BINARY_CHECKSUM(*)) siempre entrega 0 para las 3 tablas con contenido diferente!


SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM 
(
  SELECT 1 as numA, 1 as numB
  UNION ALL
  SELECT 1 as numA, 1 as numB
)  q
-- delivers 0!

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 1 as numA, 2 as numB UNION ALL SELECT 1 as numA, 2 as numB ) q -- delivers 0!

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 0 as numA, 0 as numB UNION ALL SELECT 0 as numA, 0 as numB ) q -- delivers 0!

 30
Author: BitLauncher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-29 02:34:15

¿Por qué no quieres usar disparadores? Son algo bueno si los usas correctamente. Si los usas como una forma de hacer cumplir la integridad referencial, es cuando van de bueno a malo. Pero si los utiliza para el monitoreo, realmente no se consideran tabú.

 26
Author: Nick Berardi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-26 17:38:44

¿Con qué frecuencia necesita verificar los cambios y cuán grandes (en términos de tamaño de fila) son las tablas en la base de datos? Si utiliza el método CHECKSUM_AGG(BINARY_CHECKSUM(*)) sugerido por John, escaneará cada fila de la tabla especificada. La sugerencia NOLOCK ayuda, pero en una base de datos grande, todavía está golpeando cada fila. También tendrá que almacenar la suma de verificación para cada fila para que diga que una ha cambiado.

¿Has considerado abordar esto desde un ángulo diferente? Si no desea modificar el esquema para agregar disparadores, (lo cual tiene sentido, no es su base de datos), ¿ha considerado trabajar con el proveedor de aplicaciones que hace la base de datos?

Podrían implementar una API que proporcione un mecanismo para notificar a las aplicaciones accesorias que los datos han cambiado. Podría ser tan simple como escribir en una tabla de notificación que enumera qué tabla y qué fila se modificaron. Eso podría implementarse a través de disparadores o código de aplicación. Por tu parte, ti no importaría, tu única preocupación estaría escaneando la tabla de notificaciones de forma periódica. El golpe de rendimiento en la base de datos sería mucho menor que escanear cada fila en busca de cambios.

La parte difícil sería convencer al proveedor de la aplicación para implementar esta característica. Dado que esto se puede manejar completamente a través de SQL a través de disparadores, podría hacer la mayor parte del trabajo para ellos escribiendo y probando los disparadores y luego trayendo el código al proveedor de la aplicación. Al hacer que el proveedor admita los desencadenantes, evita la situación en la que la adición de un disparador reemplaza inadvertidamente un disparador suministrado por el proveedor.

 20
Author: Chris Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-14 12:19:25

Tiene un trabajo DTS (o un trabajo iniciado por un servicio de Windows) que se ejecuta en un intervalo determinado. Cada vez que se ejecuta, obtiene información sobre la tabla dada utilizando las tablas system INFORMATION_SCHEMA, y registra estos datos en el repositorio de datos. Compare los datos devueltos con respecto a la estructura de la tabla con los datos devueltos la vez anterior. Si es diferente, entonces sabes que la estructura ha cambiado.

Consulta de ejemplo para devolver información sobre todos de las columnas en la tabla ABC (idealmente listando solo las columnas de la tabla INFORMATION_SCHEMA que desee, en lugar de usar *select ** como hago aquí):

select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'

Supervisaría diferentes columnas y vistas INFORMATION_SCHEMA dependiendo de cómo defina exactamente "cambios en una tabla".

 18
Author: Yaakov Ellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-01 14:06:28

Desafortunadamente, no creo que haya una manera limpia de hacer esto en SQL2000. Si limita sus requisitos a SQL Server 2005 (y posteriores), entonces está en el negocio. Puede usar la clase SQLDependency en System.Data.SqlClient. Ver Notificaciones de consulta en SQL Server (ADO.NET).

 18
Author: caryden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-25 20:42:28

Adivina aquí: Si no quieres modificar las tablas de terceros, ¿puedes crear una vista y luego poner un disparador en esa vista?

 13
Author: Orion Edwards,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-05 01:12:37

Compruebe la última fecha de confirmación. Cada base de datos tiene un historial de cuándo se realiza cada confirmación. Creo que es un estándar de cumplimiento ÁCIDO.

 7
Author: ECE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-24 04:58:25