Mysql
 sql >> Base de données >  >> RDS >> Mysql

Stockez toutes les modifications de données avec tous les détails (comme Stackoverflow)

J'y pense depuis un moment maintenant et je ne peux penser qu'à deux façons de le faire. Les deux peuvent fonctionner de manière totalement transparente lorsqu'ils sont intégrés dans une couche / un modèle de données abstrait.

Soit dit en passant, il existe une implémentation pour les données de table "versionnables" dans la doctrine du mappeur ORM. Voir cet exemple dans leur documentation . Peut-être que cela correspond à vos besoins, mais cela ne correspond pas aux miens. Il semble supprimer toutes les données d'historique lorsque l'enregistrement d'origine est supprimé, ce qui le rend peu sûr pour les révisions.

Option A :disposer d'une copie de chaque table pour conserver les données de révision

Supposons que vous disposiez d'un simple tableau de contacts :

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

Vous créeriez une copie de cette table et ajouteriez des données de révision :

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)
)

Gardez une trace de INSERT et UPDATE en utilisant AFTER déclencheurs. A chaque nouvelle révision de données dans l'original, insérez une copie des nouvelles données dans la table de révision et définissez le type de modification correctement.

Pour enregistrer un DELETE révisionnellement sûr, vous devez également insérer une nouvelle ligne dans la table d'historique ! Pour cela, vous devez utiliser un BEFORE DELETE déclencher et stocker les dernières valeurs avant qu'elles ne soient supprimées. Sinon, vous devrez supprimer chaque NOT NULL contrainte dans la table d'historique également.

Quelques remarques importantes concernant cette implémentation

  • Pour la table d'historique, vous devez supprimer chaque UNIQUE KEY (ici :la PRIMARY KEY ) de la table de révision, car vous aurez plusieurs fois la même clé pour chaque révision de données.
  • Lorsque vous ALTER le schéma et les données de la table d'origine via une mise à jour (par exemple, une mise à jour logicielle), vous devez vous assurer que les mêmes données ou corrections de schéma sont également appliquées à la table d'historique et à ses données. Sinon, vous rencontrerez des problèmes lors du retour à une ancienne révision d'un jeu d'enregistrements.
  • Dans une implémentation réelle, vous voudriez savoir quel utilisateur a modifié les données. Pour avoir cette sécurité de révision, un enregistrement d'utilisateur ne doit jamais être supprimé de la table des utilisateurs. Vous devez simplement désactiver le compte avec un indicateur.
  • Généralement, une seule action utilisateur implique plusieurs tables. Dans une implémentation réelle, vous devrez également suivre les modifications apportées à plusieurs tables qui appartiennent à une seule transaction utilisateur et également dans quel ordre. Dans un cas d'utilisation réel, vous voudriez annuler toutes les modifications d'une seule transaction ensemble, dans l'ordre inverse. Cela nécessiterait une table de révision supplémentaire qui assure le suivi des utilisateurs et des transactions et entretient une relation lâche avec toutes ces révisions individuelles dans les tables d'historique.

Avantages :

  • complètement dans la base de données, indépendamment du code de l'application. (enfin, pas lorsque le suivi des transactions des utilisateurs est important. cela nécessiterait une certaine logique en dehors de la portée de la requête unique)
  • toutes les données sont dans leur format d'origine, pas de conversions de type implicites.
  • bonnes performances de recherche dans les révisions
  • restauration facile. Faites juste un simple INSERT .. ON DUPLICATE KEY UPDATE .. déclaration sur la table d'origine, en utilisant les données de la révision que vous souhaitez annuler.

Mérite :

  • Difficile à mettre en œuvre manuellement.
  • Difficile (mais pas impossible) à automatiser lorsqu'il s'agit de migrations de bases de données/de mises à jour d'applications.

Comme déjà indiqué ci-dessus, doctrines versionable fait quelque chose de similaire.

Option B :disposer d'un tableau central des journaux des modifications

préface :mauvaise pratique, présentée uniquement à titre d'illustration de l'alternative.

Cette approche repose fortement sur la logique de l'application, qui doit être cachée dans une couche/un modèle de données.

Vous disposez d'une table d'historique centrale qui assure le suivi de

  • Qui a fait
  • quand
  • modifier, insérer ou supprimer
  • quelles données
  • dans quel champ
  • de quel tableau

Comme dans l'autre approche, vous pouvez également vouloir suivre quelles modifications de données individuelles appartiennent à une action/transaction utilisateur unique et dans quel ordre.

Avantages :

  • inutile de rester synchronisé avec la table d'origine lors de l'ajout de champs à une table ou de la création d'une nouvelle table. il évolue de manière transparente.

Mérite :

  • mauvaise pratique en utilisant une valeur simple =magasin de clés dans la base de données
  • mauvaises performances de recherche, en raison de conversions de type implicites
  • peut ralentir les performances globales de l'application/de la base de données, lorsque la table d'historique centrale devient un goulot d'étranglement en raison de verrous en écriture (cela ne s'applique qu'à des moteurs spécifiques avec des verrous de table, c'est-à-dire MyISAM)
  • Il est beaucoup plus difficile de mettre en œuvre des rollbacks
  • erreurs de conversion de données possibles/perte de précision en raison de la conversion de type implicite
  • ne garde pas une trace des modifications lorsque vous accédez directement à la base de données quelque part dans votre code au lieu d'utiliser votre modèle/couche de données et oubliez que dans ce cas, vous devez écrire manuellement dans le journal de révision. Peut être un gros problème lorsque vous travaillez en équipe avec d'autres programmeurs.

Conclusion :

  • Option B peut être très pratique pour les petites applications en tant que simple "drop in" lorsque c'est juste pour enregistrer les modifications.
  • Si vous souhaitez remonter dans le temps et pouvoir comparer facilement les différences entre la révision historique 123 à la révision 125 et/ou revenir aux anciennes données, puis Option A est le chemin le plus difficile.