¿Cómo se almacena generalmente la grabación de cada cambio de una fila en una base de datos?

10

En un proyecto en el que estoy trabajando, cada cambio en las filas en algunas tablas de la base de datos debe ser rastreado para una auditoría o reversión posterior. Debe ser fácil encontrar quién modificó la fila, desde qué dirección IP y cuándo, y poder restaurar la versión anterior.

Lo mismo se utiliza, por ejemplo, por Stack Exchange. Cuando cambio la pregunta de otra persona, es posible descubrir que la cambié y revertir los cambios.

¿Cuál es la técnica general utilizada para almacenar cada cambio en un objeto en una base de datos , dado que mi esquema actual tiene principalmente las mismas propiedades (a continuación) que una aplicación comercial promedio?

  • Los objetos tienen un tamaño relativamente pequeño: puede haber algunos, nvarchar(1000)por ejemplo, pero no grandes cantidades de datos binarios, este se almacena directamente en el disco y se accede directamente, y no a través de Microsoft SQL filestream,
  • La carga de la base de datos es bastante baja y toda la base de datos es manejada por una máquina virtual en un servidor,
  • El acceso a las versiones anteriores no tiene que ser tan rápido como el acceso a la última versión, pero debe estar actualizado¹ y no demasiado lento².

<tl-dr>

Pensé en los siguientes casos, pero no tengo experiencia real con ese tipo de escenarios, por lo que escucharía las opiniones de otros:

  1. Almacene todo en la misma tabla, distinguiendo las filas por ID y versión. En mi opinión, es muy estúpido y dolerá tarde o temprano en el nivel de rendimiento. Con este enfoque, también es imposible establecer un nivel de seguridad diferente para los últimos elementos y el seguimiento de versiones. Finalmente, cada consulta sería más complicada de escribir. En realidad, para acceder a los datos actualizados, me vería obligado a agrupar todo por ID y recuperar, en cada grupo, la última versión.

  2. Almacene la última versión en una tabla y, en cada cambio, copie la versión obsoleta en otra tabla en otro esquema. La falla es que siempre almacenamos todos los valores, incluso si no cambiaron. Establecer valores sin cambios en nullno es una solución, ya que también debo rastrear cuándo se cambia el valor hacia nullo desde null.

  3. Almacene la última versión en una tabla y la lista de propiedades modificadas con sus valores anteriores en otra tabla. Esto parece tener dos defectos: el más importante es que la única forma de ordenar tipos heterogéneos de valores anteriores en la misma columna es tener un binary(max). El segundo es que, creo, sería más difícil usar dicha estructura cuando se muestran las versiones anteriores al usuario.

  4. Haga lo mismo que en dos puntos anteriores, pero almacene las versiones en una base de datos separada. En cuanto al rendimiento, puede ser interesante para evitar ralentizar el acceso a las últimas versiones al tener las versiones anteriores en la misma base de datos; Aún así, creo que es una optimización prematura y debe hacerse solo si hay una prueba de que tener versiones anteriores y más recientes en la misma base de datos es un cuello de botella.

</tl-dr>


¹ Por ejemplo, sería inaceptable almacenar los cambios en un archivo de registro, como se hace para los registros HTTP, y vaciar los datos del registro a la base de datos por la noche cuando la carga del servidor es más baja. La información sobre las diferentes versiones debe estar disponible de forma inmediata o casi inmediata; Un retraso de unos segundos es aceptable.

² No se accede a la información con mucha frecuencia y solo por un grupo específico de usuarios, pero aún así, sería inaceptable forzarlos a esperar 30 segundos para que se muestre la lista de versiones. Nuevamente, un retraso de unos segundos es aceptable.

Arseni Mourzenko
fuente
3
Relevante: Captura de datos de cambio de SQL Server .
Nick Chammas

Respuestas:

8

La forma normal de auditar el registro de este tipo es tener una tabla oculta y registrar los cambios con disparadores en la tabla base que está auditando. Las otras tablas se pueden colocar en un disco físico diferente si lo necesita para el rendimiento, y puede colocar índices en ellas si necesita soportar la recuperación rápida de los datos.

Las tablas tendrán aproximadamente la misma estructura que las tablas originales, pero tendrán una columna de fecha y hora para cuando se produjo el cambio y un marcador para saber si la fila se insertó, cambió o eliminó. La secuencia de las versiones se puede hacer por la marca de tiempo.

La fecha de cambio se puede hacer haciendo que la columna datetime no sea nula con un valor predeterminado de getdate (); una columna de usuario de auditoría capturará al usuario con una columna no nula predeterminada en Suser_Sname (). Suponiendo que el usuario real se está suplantando en la sesión, esto capturará la identidad del usuario que realiza el cambio.

La base de datos no tiene forma de conocer la dirección IP que se conecta a un servidor web. La aplicación tendrá que capturar y registrar explícitamente la dirección IP con la transacción.

Si tiene una gran cantidad de tablas que desea auditar, puede usar los metadatos del diccionario de datos del sistema para generar los desencadenantes mediante programación.

Esta solución es, con mucho, la mejor por varias razones:

  • Captura cualquier cambio en la tabla, no solo los realizados por la aplicación.

  • Las tablas de auditoría se pueden colocar en un conjunto diferente de discos para reducir la carga de E / S en sus tablas primarias.

  • Puede usar una vista basada en una unión de la tabla y la tabla de registro de auditoría para que muestre todo el historial, incluida la versión actual.

  • Puede indexar las tablas de registro de auditoría según sea necesario para que los usuarios de auditoría puedan consultarlas de manera receptiva. Como de costumbre, la selección de índice es una compensación entre el rendimiento de la consulta y la sobrecarga de actualización.

Preocupado por TunbridgeWells
fuente
intenta decir si tengo 1000 tablas que necesito mantener en el registro para cualquier cambio, entonces tengo que crear 1000 tablas de sombra, ¿eh? y 1000 disparadores para capturar el cambio? en caso afirmativo, es una idea falsa ... podemos crear una sola tabla de historial y un solo disparador para capturar y registrar los datos modificados. podemos almacenar datos de filas antiguas y nuevas en esa tabla como un xml ... eso es lo que mucha gente hace ... ¡estoy claro!
Thomas
1
Para 1000 tablas, escribe una utilidad que lee las definiciones del diccionario de datos del sistema y genera los desencadenantes y las definiciones de tabla. Lo hice en un sistema con 560 tablas y funciona bien.
Preocupado
0

Sé de muchos sistemas CMS (incluido Wordpress) que usan una sola tabla para almacenar todas las versiones de los datos. Pero, de nuevo, solo tienen que hacer esto para la tabla que tiene las publicaciones del blog. Vea la estructura de la base de datos de Wordpress .

Además, el número de registros y el número de revisiones por las que pasa cada fila jugarán un papel importante en su decisión.

Dharmendar Kumar 'DK'
fuente
0

Acerca del control de versiones de CMS; para drupal crea una tabla especial para cada campo de la entidad que almacena el valor anterior; tal concepto le permite una buena manipulación de sus datos, pero creo que es costoso, mi propia solución es convertir mi objeto a formato xml y almacenarlo como una cadena con los otros campos (tiempo de cambio, id ...)

Bourkadi
fuente