¿Buscar cambios en una tabla de SQL Server?

142

¿Cómo puedo monitorear una base de datos de SQL Server en busca de cambios en una tabla sin usar activadores o modificar la estructura de la base de datos de alguna manera? Mi entorno de programación preferido es .NET y C #.

Me gustaría poder admitir cualquier SQL Server 2000 SP4 o posterior. Mi aplicación es una visualización de datos atornillada para el producto de otra compañía. Nuestra base de clientes es de miles, por lo que no quiero tener que exigir que modifiquemos la tabla de proveedores externos en cada instalación.

Por "cambios en una tabla" quiero decir cambios en los datos de la tabla, no 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 a intervalos.


Parece que el mejor curso de acción dados mis requisitos (sin desencadenantes o modificación del esquema, SQL Server 2000 y 2005) es utilizar la BINARY_CHECKSUMfunción en T-SQL . La forma en que planeo implementar es esta:

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, revise la tabla fila por fila usando la consulta:

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

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

TimM
fuente
3
No pusieron una última marca de tiempo modificada en sus filas, ¿verdad?
zmbq
Para el registro, si el soporte de la versión es SQL Server 2005 o posterior. Echaré un vistazo a la función Service Broker de SQL Server.
Marco Guignard el

Respuestas:

97

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 que el contenido de la tabla no haya cambiado. Vea mi publicación sobre esto para más información:

CHECKSUM

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

Jon Galloway
fuente
2
Las sumas de verificación pueden y fallarán eventualmente. Si su sistema acepta que dos conjuntos de datos diferentes resultarán en la misma suma de comprobación, entonces está bien. Por esa razón, tuve que alejarme de las sumas de verificación en la mayoría de nuestros sistemas ...
LPains
@LPains, ¿puede explicar su declaración?
petrosmm
1
@petrosmm No estoy seguro de qué quieres específicamente que elabore, pero lo intentaré. Imagine que tiene una tabla con unos cientos de registros, esencialmente genera un número entero como suma de verificación, ¿con qué frecuencia va a colisionar? En mi caso, estaba haciendo eso con aproximadamente 10 tablas, todas con cientos de registros. Tuve al menos una colisión por día. Comprueba esta otra respuesta stackoverflow.com/questions/14450415/…
LPains
29

Lamentablemente, CHECKSUM no siempre funciona correctamente para detectar cambios .

Es solo una suma de control primitiva y ningún cálculo de verificación de redundancia cíclica (CRC).

Por lo tanto, no puede usarlo para detectar todos los cambios, por ejemplo, los cambios simétricos dan como resultado el mismo CHECKSUM.

P.ej. la solución CHECKSUM_AGG(BINARY_CHECKSUM(*))siempre entregará 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!

Lanzador de Bit
fuente
55
Eso no es realmente una respuesta, es "su sugerencia no funciona".
kristianp
1
Esto puede remediarse para datos duplicados utilizando la palabra clave DISINCT antes de BINARY_CHECKSUM. Aquí se discuten algunos otros escollos , pero no son exactamente escenarios comunes.
pblack
25

¿Por qué no quieres usar disparadores? Son buenos si los usa correctamente. Si los usa como una forma de hacer cumplir la integridad referencial, es cuando pasan de bueno a malo. Pero si los usa para monitorear, en realidad no se consideran tabú.

Nick Berardi
fuente
20

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

¿Has considerado ir a esto desde un ángulo diferente? Si no desea modificar el esquema para agregar desencadenantes (lo cual tiene sentido, no es su base de datos), ¿ha considerado trabajar con el proveedor de la aplicación 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 su parte, usted no importaría, su única preocupación sería escanear la tabla de notificaciones periódicamente. El rendimiento alcanzado 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 función. Dado que esto se puede manejar completamente a través de SQL a través de disparadores, puede hacer la mayor parte del trabajo por ellos escribiendo y probando los disparadores y luego llevando el código al proveedor de la aplicación. Al hacer que el proveedor admita los desencadenantes, evita la situación en la que agregar un desencadenador reemplaza inadvertidamente un desencadenante suministrado por el proveedor.

Chris Miller
fuente
18

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

Carryden
fuente
16

Tener 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 usando las tablas INFORMATION_SCHEMA del sistema 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.

Ejemplo de consulta para devolver información sobre todas las columnas de la tabla ABC (idealmente enumerando solo las columnas de la tabla INFORMATION_SCHEMA que desea, en lugar de usar * select ** como lo hago aquí):

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

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

Yaakov Ellis
fuente
2
La pregunta es acerca de los cambios en los datos de la tabla y el esquema_información contiene el esquema (definiciones de columna) de la tabla.
también
13

Adivina aquí: si no quieres modificar las tablas de terceros, ¿puedes crear una vista y luego activarla?

Orion Edwards
fuente
6

Verifique 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 de ACID.

ECE
fuente
1
Proporcione una forma documentada de obtener esta información en una tabla en SQL Server
Martin Smith