¿Buscar cambios en una tabla de SQL Server?

¿Buscar cambios en una tabla de SQL Server?

¿Cómo puedo monitorear una base de datos de SQL Server para detectar cambios en una tabla sin usar disparadores 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 más reciente . 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.


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

Cada X segundos ejecuta la siguiente consulta:

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

Y compara 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.

Mostrar la mejor respuesta

No pusieron una última marca de tiempo modificada en sus filas, ¿verdad?

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.

¿Por qué no quieres usar disparadores? Son algo bueno si los usas 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ú.

Avatar too

La pregunta es sobre los cambios en los datos de la tabla y el esquema de información contiene un esquema (definiciones de columna) de la tabla.

Eche 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 obtener 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 disparadores)

Las sumas de verificación pueden y fallarán eventualmente. Si su sistema acepta que dos conjuntos diferentes de datos resultarán en la misma suma de verificación, entonces usted está bien. Por esa razón, tuve que alejarme de las sumas de verificación en la mayoría de nuestros sistemas ...

@LPains, ¿puede explicar su declaración?

@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 comprobació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. Verifique esta otra respuesta stackoverflow.com/questions/14450415/…

¿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 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á 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 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 mediante disparadores o código de aplicación. Por su parte, 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.

Adivinanza aquí: si no desea modificar las tablas de terceros, ¿puede crear una vista y luego activar la vista?

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. Puede usar la clase SQLDependency en System.Data.SqlClient . Consulte Notificaciones de consulta en SQL Server (ADO.NET) .

Lamentablemente, CHECKSUM no siempre funciona correctamente para detectar cambios .

Es solo una suma de comprobación 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, e. sol. ¡los cambios simétricos dan como resultado el mismo CHECKSUM!

E. sol. la solución con 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!

Eso no es realmente una respuesta, es "su sugerencia no funciona".

Esto puede remediarse para datos duplicados mediante el uso de la palabra clave DISINCT antes de BINARY_CHECKSUM. Hay algunas otras dificultades discutidas aquí pero no exactamente comunes escenarios

Avatar ECE

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.

Proporcione una forma documentada de obtener esta información en una tabla en SQL Server