Formas de tener un historial de cambios en las entradas de la base de datos

21

¿Cuáles son las formas de permitir el control de versiones de las entradas de la base de datos (datos)?

Piense en las habilidades de los sistemas de gestión de contenido para revertir los cambios de los artículos.

¿Cuáles son sus pros / contras?

matcauthon
fuente
1
¿Qué es exactamente lo que quieres versionar? ¿El esquema o los datos?
tdammers
1
Quiero versionar los datos. Para permanecer en el ejemplo de cms, digamos las versiones de los artículos .
matcauthon
Es posible que desee ver en Datomic.
dan_waterworth

Respuestas:

19

Básicamente, hay dos enfoques: una tabla de auditoría, con todos los valores anteriores almacenados en ella, o incluir una fecha de inicio / finalización como parte de la tabla, y todas las actualizaciones crean un nuevo registro mientras se cierra el anterior.

Actualización: SQL SERVER 2016 admite esto como un patrón de diseño / tipo de tabla: https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-2017

jmoreno
fuente
44
Entonces, el primer enfoque podría ser más escalable. Como los datos "archivados" rara vez serán accedidos, el diseño de la base de datos podría optimizarse. Y la mesa de trabajo se mantiene pequeña. Dependiendo de la complejidad, también debería ser posible guardar solo diferencias. ¿Es aconsejable usar el patrón de recuerdo ?
matcauthon
1
Eso dependerá de su uso, puede ser suficiente usar desencadenantes para llenar la tabla / s y luego proporcionar una forma de elegir qué y hasta dónde retroceder.
jmoreno
Tienes un error tipográfico en tu respuesta (el patrón debe ser un patrón)
geocodezip
7

Una idea es utilizar "Bases de datos de solo inserción". La idea básica es que nunca elimines o actualices datos en una fila .

Cada tabla que se debe rastrear tendrá dos datetimecolumnas fromy to. Comienzan con el valor NULLen cada uno (principio del tiempo hasta el final del tiempo). Cuando necesita "cambiar" la fila, agrega una nueva fila y, al mismo tiempo, actualiza la tofila anterior Nowy fromla fila a la que está agregando Now.

Para obtener información más detallada, consulte:

Esta técnica se llama AuditTrailpara administrar datos heredados y almacena un poco el historial de cambios.

Parece que ya se ha publicado una pregunta de esta naturaleza:

Yusubov
fuente
Lamentablemente, esa pregunta parece haber sido eliminada :(
Douglas Gaskell
No hay problema, aquí está el enlace . Otra buena sugerencia de diseño en el enlace
Yusubov
2

Creo que puede usar desencadenantes para cada tabla y mantener los datos en _historia (o puede dar cualquier nombre) y en cada inserción, actualización, eliminación en la tabla principal activará su desencadenador y puede guardar los detalles en esta tabla. también está disponible con la base de datos SQLite si está utilizando uno.

Este mecanismo también es útil para grandes proyectos. En esta tabla puede registrar información del usuario que ha realizado los cambios junto con la marca de tiempo de los cambios. luego puede restaurar su tabla a cualquiera de las marcas de tiempo que coincidan con sus requisitos.

Cada base de datos tiene su propia forma de escribir y codificar desencadenantes. Si está utilizando SQLite, visite SQLite.org para obtener la sintaxis. Para otras bases de datos, puede visitar sus sitios oficiales.

PYME
fuente
1

Probablemente conozca el motor Sqlite db. Toda la base de datos se guarda en un solo archivo. La API también es compatible con sistemas de archivos virtuales, por lo que básicamente puede organizar el almacenamiento en cualquier lugar y con cualquier formato, simplemente responder a las operaciones de lectura y escritura en desplazamientos de archivos particulares. Las posibles aplicaciones para esto podrían ser cifrado, compresión, etc. La mejor parte es que la capa del contenedor no debe saber nada sobre bases de datos, formato de archivo sql o sqlite, solo obedece las devoluciones de llamada xRead y xWrite.

Una de las ideas era implementar la función de máquina del tiempo. Por lo tanto, cualquier operación de xWrite guarda cada segmento que sobrescribiría en el historial de "deshacer" y el usuario puede elegir una fecha en el pasado para ver qué contenía la base de datos (probablemente en modo de solo lectura). Todavía no tengo un ejemplo de trabajo (hubo una discusión al respecto en la lista de correo sqlite), pero probablemente otros motores suministran API VFS, por lo que es posible algo similar. Y una vez implementado, debería ser compatible con estructuras de bases de datos de cualquier complejidad.

Maksee
fuente
¿Cuál crees que es este enfoque escalable para proyectos más grandes?
matcauthon
Creo que esto podría agregar una gran sobrecarga de datos para grandes cambios de datos (obviamente, ya que cada cambio debería guardarse, aunque la compresión para versiones anteriores puede ayudar). Aparte de eso desde el punto de vista de usted de su esquema, siempre que funcione para dos tablas, funcionará para veinte.
Maksee
1

El método que usamos para versionar las entradas de la base de datos es usar una tabla de auditoría. La tabla tiene un esquema en la línea de:

Seq      - Int      ' Unique identifier for this table
Event    - Char     ' Insert / Update / Delete
TblName  - Char     ' Table that had field value changed
FldName  - Char     ' Field that was changed
KeyValue - Char     ' delimited list of values for fields that make up the PK of table changed
UsrId    - Char     ' User who made the change
OldValue - Char     ' Old value (converted to character)
NewValue - Char     ' New value (converted to character)
AddTs    - DateTime ' When the change was made

Luego tenemos activadores en Insertar / Actualizar / Eliminar de las tablas que queremos rastrear.

Pros:

  • Todos los datos están en una tabla.
  • Se puede configurar para rastrear todos los campos o campos específicos en una tabla
  • Versiones fáciles de mostrar en cada campo para una tabla

Contras:

  • Tener toda la información de auditoría en una tabla da como resultado un número extremadamente grande de registros
  • Se necesitan muchos desencadenantes
briddums
fuente
0

Estoy haciendo una versión de esto ahora. para cada registro tengo una fecha insertada, una fecha modificada y una marca booleana de registro activo. Para la inserción inicial, las fechas insertadas y modificadas se establecen en Now () (este ejemplo está en Access) y el indicador de registro activo se establece en true. luego, si modifico ese registro, copio todo a un nuevo registro, cambiando los campos que está cambiando el usuario, dejo la fecha de inserción igual a la original y cambio la fecha de modificación a Ahora (). Luego volteo la bandera de Registro Activo del registro original a falsey el nuevo registro a true. También tengo un campo para ModifiedRecordsParentID donde guardo la identidad del registro original.

Entonces, si incluso necesito consultar, solo puedo devolver los registros donde ActiveRecord = truey solo obtendré la información más actualizada.

Puntilla
fuente
No hay necesidad de la ActiveRecordbandera. La fila MAX (*) siempre debe ser el registro actual. La restauración a una versión anterior simplemente inserta dicha fila en la tabla nuevamente.
invertir
No estaba seguro de cómo hacer que la selección funcionara, pero ahora que lo estás llamando, lo estoy pensando y tengo una idea, hmmmm
Brad
Por lo general, MAX (nombre_columna) selecciona el valor más grande en la columna de la tabla. Para seleccionar toda la fila, select top 1 order by id descendingse hará un simple .
invertir
Sí, eso funciona para un registro único simple, pero mi tabla era una colección de registros secundarios que tendrían que seleccionarse de inmediato, pero podrían haber sido modificados individualmente. Solo un poco más complejo.
Brad