Detectar cambios en una tabla de SQL Server


13

En mi aplicación, con una base de datos ejecutándose en SQL Server 2012, tengo un trabajo (tarea programada) que ejecuta periódicamente una consulta costosa y escribe los resultados en una tabla que luego puede consultar la aplicación.

Idealmente, me gustaría ejecutar esa consulta costosa solo si algo ha cambiado desde la última ejecución de la consulta. Dado que las tablas de origen son muy grandes, no puedo seleccionar una suma de verificación sobre todas las columnas candidatas o algo así.

Tengo las siguientes ideas:

  • Escriba explícitamente una última marca de tiempo modificada, un indicador de "deben ser consultas", o algo así en una tabla de seguimiento cada vez que cambie algo en una tabla de origen.
  • Usa un gatillo para hacer lo mismo.

Sin embargo, me gustaría saber si hay una forma ligera de detectar cambios en una tabla sin que yo haga un seguimiento explícito de las escrituras. ¿Puedo, por ejemplo, obtener el "actual" ROWVERSIONde una tabla o algo así?

Respuestas:


14

No, no hay ninguno. Cualquier tipo de seguimiento de 'última actualización en' tendría un grave problema de rendimiento, ya que todas las actualizaciones, de todas las transacciones, intentarían actualizar el registro que rastrea la 'última actualización en'. Esto significaría en la práctica sólo una transacción puede actualizar la tabla en cualquier momento, y todas las demás transacciones que esperar a que el primero en comprometerse . Serialización completa. El número de administradores / desarrolladores dispuestos a soportar tal penalización de rendimiento solo para el beneficio de saber cuándo ocurrió la última actualización es probablemente pequeño.

Por lo tanto, está obligado a manejarlo a través de un código personalizado. Eso significa desencadenantes ya que la alternativa (detección desde registros de registro) es una prerrogativa reservada solo para la replicación transaccional (o es un alter-ego CDC ). Tenga en cuenta que si intenta rastrearlo a través de una columna de 'última actualización a las', se enfrentará exactamente al problema de serialización mencionado anteriormente. Si la simultaneidad de actualización es importante, entonces tendría que usar un mecanismo de cola (el disparador usa un INSERT y luego un proceso agrega los valores insertados para formular la 'última actualización en'). No intente hacer trampa con alguna solución 'inteligente' como escabullirse de la identidad actual o buscar sys.dm_db_index_usage_stats . Y también una columna por registro 'updated_at', como las marcas de tiempo de Rails,

¿Hay alguna alternativa 'ligera'? En realidad, hay uno, pero es difícil decir si funcionará para usted y es difícil hacerlo bien: notificaciones de consulta . La Notificación de consulta hace exactamente eso, configurará una notificación si algún dato tiene cambios y necesita actualizar su consulta. Aunque la mayoría de los desarrolladores están familiarizados solo con su encarnación .Net como SqlDependency, Query Notification puede usarse como un mecanismo persistente y de larga duración para detectar cambios en los datos. En comparación con el verdadero seguimiento de cambios, será realmente liviano y su semántica está más cerca de sus necesidades (algo, cualquier cosa , ha cambiado, por lo que debe volver a ejecutar la consulta).

Pero al final, en su lugar, realmente reconsideraría mis suposiciones y volvería a la mesa de dibujo. Quizás pueda usar el envío de registros o la replicación para configurar una base de datos de informes en un servidor diferente. Lo que leí entre líneas es que necesitas una tubería ETL adecuada y un almacén de datos analíticos ...


Entonces, ¿por qué Microsoft se molestaría en crear sys.dm_db_index_usage_stats, si no se puede confiar en la información que proporciona?
Craig Efrein

No es un DMV diseñado para el seguimiento de cambios . Es muy confiable para el propósito previsto, que es el ajuste del rendimiento.
Remus Rusanu

8

Parece que llegué dos años tarde al juego, aquí, pero de hecho hay una forma bastante liviana de hacer lo que estás pidiendo.

Hay dos mecanismos de SQL Server que pueden ayudarlo. Su solución definitiva podría ser un híbrido de los dos.

Seguimiento de cambios . SQL Server tiene la capacidad de colocar tablas específicas bajo observación, registrando solo qué filas han cambiado (por su valor de clave principal) y qué tipo de cambio fue (Insertar, Actualizar o Eliminar). Una vez que configura la detección de cambios en un conjunto de tablas, una consulta liviana puede decirle si se han realizado cambios en la tabla desde la última vez que lo revisó. La sobrecarga es aproximadamente lo mismo que mantener un índice simple adicional.

Rowversion / marca de tiempo . Este es un tipo de columna varbinary de 8 bytes (convertible a BigInt) que se incrementa, en toda la base de datos, cada vez que se inserta o actualiza una fila que contiene una (no ayuda con las eliminaciones). Si indexó estas columnas, podría saber fácilmente si los datos de la fila han cambiado comparando el MAX (marca de tiempo) con su valor desde la última vez que se evaluó. Dado que el valor está aumentando monotónicamente, esto le daría una indicación confiable de que los datos han cambiado si el nuevo valor es mayor que la última vez que lo verificó.


7

Si la fuente es solo de inserción, dele una IDENTITYcolumna. Cuando realiza la transferencia de datos, registra el valor más alto escrito. Durante la próxima transferencia, solo necesita consultar valores mayores que los registrados durante la transferencia anterior. Hacemos esto para transferir registros de registros a un almacén de datos.

Para filas actualizables, agregue una bandera "sucia". Tendrá tres valores: limpio, sucio y eliminado. Las consultas del día a día tendrán que omitir filas con el indicador establecido en "eliminado". Esto será costoso en mantenimiento, pruebas y tiempo de ejecución. Después de la consulta grande, debe mencionar que todas las filas marcadas para eliminar deben eliminarse y restablecer el marcador para todas las demás. Esto no escalará bien.

Una alternativa más ligera a Change Data Capture es Change Tracking . No le dirá qué valores cambiaron, solo que la fila ha cambiado desde la última consulta. Las funciones integradas facilitan la recuperación de los valores modificados y la gestión del seguimiento. Hemos tenido éxito al usar CT para procesar aproximadamente 100,000 cambios por día en una tabla de 100,000,000 filas.

Las notificaciones de consulta siguen actuando en una palanca más alta, al nivel de un conjunto de resultados. Conceptualmente, es como definir una vista. Si SQL Server detecta que cualquier fila devuelta a través de esa vista ha cambiado, envía un mensaje a la aplicación. No hay indicación de cuántas filas cambiaron o qué columnas. Solo hay mensajes simples que dicen "algo sucedió". Depende de la aplicación preguntar y reaccionar. Prácticamente es mucho más complejo que eso, como te puedes imaginar. Existen restricciones sobre cómo se puede definir la consulta y la notificación puede activarse por condiciones que no sean datos modificados. Cuando se activa la notificación, se elimina. Si posteriormente se realiza una actividad de interés adicional, no se enviará ningún otro mensaje.

En el contexto de la pregunta del OP, QN tendrá la ventaja de tener una sobrecarga baja para configurar y un bajo costo de tiempo de ejecución. Puede ser un esfuerzo significativo establecer y mantener un riguroso régimen de suscripción-mensaje-reacción. Dado que la tabla de datos es grande, es probable que haya cambios frecuentes en ella, lo que significa que es probable que la notificación se active en la mayoría de los ciclos de procesamiento. Como no hay indicación de lo que cambió, el procesamiento incremental de los deltas no será posible, como lo haría con CT o CDC. La sobrecarga debida a la activación falsa es una tarea tediosa, pero incluso en el peor de los casos, la consulta costosa no necesita ejecutarse con más frecuencia de lo que es actualmente.


3

SqlTableDependency

SqlTableDependency es un componente de implementación de alto nivel para acceder a notificaciones que contienen valores de registro de tabla en la base de datos de SQL Server.

SqlTableDependency es un componente genérico de C # utilizado para recibir notificaciones cuando cambia el contenido de una tabla de base de datos especificada.

¿Cuál es la diferencia con .NET SqlDepenency?

Básicamente, la principal diferencia es que SqlTableDependency envía eventos que contienen valores para el registro insertado, modificado o eliminado, así como la operación DML (insertar / eliminar / actualizar) ejecutada en la tabla: SqlDepenency no dice qué datos se cambiaron en el tabla de base de datos, solo dicen que algo ha cambiado.

Echa un vistazo al proyecto GITHUB .


1

Si las actualizaciones que espera afectan a un índice (y solo si), puede usar la tabla del sistema sys.dm_db_index_usage_statspara detectar la última actualización de un índice en la tabla en cuestión. Usarías el last_user_updatecampo.

Por ejemplo, para obtener las tablas actualizadas más recientemente:

select
    object_name(object_id) as OBJ_NAME, *
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
order by
    dm_db_index_usage_stats.last_user_update desc

O, para verificar si se cambió una tabla específica desde una fecha específica:

select
    case when count(distinct object_id) > 0 then 1 else 0 end as IS_CHANGED
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
    and object_id = object_id('MY_TABLE_NAME')
    and last_user_update > '2016-02-18'

¿Cuál es tu opinión sobre el comentario de Remus arriba? "No intente hacer trampa con alguna solución 'inteligente' como escabullirse de la identidad actual o buscar sys.dm_db_index_usage_stats". (Ver también su comentario debajo de su respuesta.)
Fabian Schmied

1
@FabianSchmied Interesante: no había visto que cuando agregué mi respuesta no pude encontrar nada autorratativo aparte de otra de las respuestas de Remus para indicar que no es confiable para este caso de uso; la página MS dm_db_index_operational_statsmuestra problemas (borrados a medida que se borra el caché de metadatos), pero no para dm_db_index_usage_stats. El único problema que encontré fue con las reconstrucciones de índice, los reinicios del servidor y el desprendimiento de la base de datos que borraban las estadísticas de uso, y no parecía que eso se aplicara aquí. Estaría interesado en ver información comprobada sobre esto.
Geoff
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.