sql >> Base de Datos >  >> RDS >> Mysql

Almacene todos los cambios de datos con todos los detalles (como Stackoverflow)

He estado pensando en eso por un tiempo y solo puedo pensar en dos formas de hacerlo. Ambos pueden funcionar de forma totalmente transparente cuando se elaboran en una capa/modelo de datos abstractos.

Por cierto, hay una implementación para datos de tablas "versionables" en la doctrina del mapeador ORM. Vea este ejemplo en sus documentos . Tal vez eso se ajuste a tus necesidades, pero no a las mías. Parece eliminar todos los datos del historial cuando se elimina el registro original, por lo que no es realmente seguro para la revisión.

Opción A:tener una copia de cada tabla para guardar los datos de revisión

Digamos que tiene una tabla de contactos simple:

CREATE TABLE contact (
    id INT NOT NULL auto_increment,
    name VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    PRIMARY KEY (id)
)

Crearía una copia de esa tabla y agregaría datos de revisión:

CREATE TABLE contact_revisions (
    id INT NOT NULL,
    name VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    revision_id INT auto_increment,
    type ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
    change_time DEFAULT current_timestamp,
    PRIMARY KEY(revision_id)
)

Realizar un seguimiento de INSERT y UPDATE usando AFTER disparadores En cada nueva revisión de datos en el original, inserte una copia de los nuevos datos en la tabla de revisión y configure el type de modificación correctamente.

Para registrar un DELETE revisión segura, ¡también debe insertar una nueva fila en la tabla de historial! Para esto debes usar un BEFORE DELETE activar y almacenar los valores más recientes antes de que se eliminen. De lo contrario, tendrá que eliminar cada NOT NULL restricción en la tabla de historial también.

Algunas notas importantes sobre esta implementación

  • Para la tabla de historial, debe soltar cada UNIQUE KEY (aquí:la PRIMARY KEY ) de la tabla de revisión porque tendrá la misma clave varias veces para cada revisión de datos.
  • Cuando ALTER el esquema y los datos en la tabla original a través de una actualización (por ejemplo, una actualización de software), debe asegurarse de que se apliquen los mismos datos o correcciones de esquema a la tabla de historial y sus datos también. De lo contrario, tendrá problemas al volver a una revisión anterior de un conjunto de registros.
  • En una implementación del mundo real, le gustaría saber qué usuario modificó los datos. Para tener esa revisión segura, un registro de usuario nunca debe eliminarse de la tabla de usuarios. Simplemente debe establecer la cuenta deshabilitada con una bandera.
  • Por lo general, una sola acción de usuario involucra más de una tabla. En una implementación del mundo real, también tendría que realizar un seguimiento de qué cambios en varias tablas pertenecen a una sola transacción de usuario y también en qué orden. En un caso de uso real, le gustaría revertir todos los cambios de una sola transacción juntos, en orden inverso. Eso requeriría una tabla de revisión adicional que realice un seguimiento de los usuarios y las transacciones y mantenga una relación flexible con todas esas revisiones individuales en las tablas de historial.

Beneficios:

  • completamente en la base de datos, independiente del código de la aplicación. (bueno, no cuando el seguimiento de las transacciones de los usuarios es importante. Eso requeriría algo de lógica fuera del alcance de la consulta única)
  • Todos los datos están en su formato original, sin conversiones de tipos implícitas.
  • buen rendimiento en la búsqueda en las revisiones
  • retroceso sencillo. Simplemente haga un simple INSERT .. ON DUPLICATE KEY UPDATE .. declaración en la tabla original, utilizando los datos de la revisión que desea deshacer.

Méritos:

  • Difícil de implementar manualmente.
  • Difícil (pero no imposible) de automatizar cuando se trata de migraciones de bases de datos/actualizaciones de aplicaciones.

Como ya se indicó anteriormente, doctrines versionable hace algo similar.

Opción B:tener una tabla de registro de cambios central

prefacio:mala práctica, que se muestra solo como ilustración de la alternativa.

Este enfoque depende en gran medida de la lógica de la aplicación, que debe ocultarse en una capa/modelo de datos.

Tiene una tabla de historial central que realiza un seguimiento de

  • Quién lo hizo
  • cuando
  • modificar, insertar o eliminar
  • qué datos
  • en qué campo
  • de qué tabla

Al igual que en el otro enfoque, es posible que también desee realizar un seguimiento de qué cambios de datos individuales pertenecen a una sola acción/transacción de usuario y en qué orden.

Beneficios:

  • no es necesario mantener la sincronización con la tabla original cuando se agregan campos a una tabla o se crea una tabla nueva. se escala de forma transparente.

Méritos:

  • mala práctica usando un valor simple =almacén de claves en la base de datos
  • mal rendimiento de búsqueda debido a conversiones de tipos implícitas
  • puede ralentizar el rendimiento general de la aplicación/base de datos, cuando la tabla de historial central se convierte en un cuello de botella debido a bloqueos de escritura (esto solo se aplica a motores específicos con bloqueos de tabla, es decir, MyISAM)
  • Es mucho más difícil implementar reversiones
  • posibles errores de conversión de datos/pérdida de precisión debido a la conversión de tipos implícita
  • no realiza un seguimiento de los cambios cuando accede directamente a la base de datos en algún lugar de su código en lugar de usar su modelo/capa de datos y olvida que en este caso debe escribir en el registro de revisión manualmente. Puede ser un gran problema cuando se trabaja en equipo con otros programadores.

Conclusión:

  • Opción B puede ser muy útil para aplicaciones pequeñas como un simple "inicio" cuando es solo para registrar cambios.
  • Si desea retroceder en el tiempo y poder comparar fácilmente las diferencias entre la revisión histórica 123 a revisión 125 y/o volver a los datos antiguos, luego Opción A es el camino difícil a seguir.