Façons d'avoir un historique des modifications des entrées de la base de données

21

Comment autoriser le versionnage des entrées de la base de données (données)?

Pensez aux capacités des systèmes de gestion de contenu pour annuler les modifications d'articles.

Quels sont leurs avantages / inconvénients?

matcauthon
la source
1
Que voulez-vous exactement versionner? Le schéma ou les données?
tdammers
1
Je veux mettre à jour les données. Pour rester à l'exemple des cms, disons les versions des articles .
matcauthon
Vous voudrez peut-être examiner Datomic.
dan_waterworth

Réponses:

19

Il existe essentiellement deux approches: une table d'audit, avec toutes les valeurs précédentes stockées, ou inclure une date de début / fin dans le tableau, et toutes les mises à jour créent un nouvel enregistrement tout en fermant l'ancien.

Mise à jour: SQL SERVER 2016 prend en charge cela en tant que modèle de conception / type de table - https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-2017

jmoreno
la source
4
La première approche pourrait donc être plus évolutive. Les données "archivées" étant rarement accessibles, la conception de la base de données pourrait être optimisée. Et la table de travail reste petite. Selon la complexité, il devrait également être possible d'enregistrer uniquement les différences. Est-il conseillé d'utiliser le motif souvenir ?
matcauthon
1
Cela dépendra de votre utilisation, il peut être suffisant d'utiliser des déclencheurs pour remplir la / les table (s), puis fournir un moyen de choisir quoi et jusqu'où revenir.
jmoreno
Vous avez une faute de frappe dans votre réponse (le motif devrait être un motif)
geocodezip
7

Une idée consiste à utiliser des "bases de données à insertion seule". L'idée de base est de ne jamais supprimer ou mettre à jour des données sur une ligne .

Chaque table qui doit être suivie aura deux datetimecolonnes fromet to. Ils commencent par la valeur NULLde chacun (du début à la fin du temps). Lorsque vous devez "modifier" la ligne, vous ajoutez une nouvelle ligne, et en même temps vous mettez à jour la toligne précédente Nowet fromla ligne à laquelle vous ajoutez Now.

Pour plus d'informations, consultez:

Cette technique est appelée AuditTrailpour gérer les données héritées, et sa mémoire stocke un peu l'historique des modifications.

Il semble que des questions de cette nature soient déjà publiées:

Yusubov
la source
Malheureusement, cette question semble avoir été supprimée :(
Douglas Gaskell
Pas de problème, voici le lien . Une autre bonne suggestion de design dans le lien
Yusubov
2

Je pense que vous pouvez utiliser des déclencheurs pour chaque table et maintenir les données dans _history (ou vous pouvez donner n'importe quel nom) et à chaque insertion, la mise à jour, la suppression sur la table principale déclenchera votre déclencheur et vous pouvez enregistrer les détails dans cette table. est également disponible avec la base de données SQLite si vous en utilisez une.

Ce mécanisme est également utile pour les grands projets. Dans ce tableau, vous pouvez enregistrer les informations de l'utilisateur qui a effectué les modifications ainsi que l'horodatage des modifications. vous pouvez ensuite restaurer votre table selon l’horodatage correspondant à vos besoins.

Chaque base de données a sa propre façon d'écrire et de coder les déclencheurs. Si vous utilisez SQLite, visitez SQLite.org pour la syntaxe. Pour d'autres bases de données, vous pouvez visiter leurs sites officiels.

PME
la source
1

Vous connaissez probablement le moteur Sqlite db. L'ensemble de la base de données est enregistré dans un seul fichier. L'API prend également en charge les systèmes de fichiers virtuels, vous pouvez donc organiser le stockage n'importe où et avec n'importe quel format, il suffit de répondre aux opérations de lecture et d'écriture à des décalages de fichiers particuliers. Les applications possibles pour cela pourraient être le cryptage, la compression, etc. La meilleure partie est que la couche conteneur ne devrait rien savoir des bases de données, du format de fichier sql ou sqlite, obéissez simplement aux rappels xRead et xWrite.

L'une des idées était d'implémenter la fonction de machine à remonter le temps. Ainsi, toute opération xWrite enregistre chaque segment qu'elle écraserait dans l'historique "Annuler" et l'utilisateur peut choisir une date dans le passé pour voir ce que la base de données contenait (probablement en mode lecture seule). Je n'ai pas encore d'exemple de travail (il y a eu une discussion à ce sujet dans la liste de diffusion sqlite), mais probablement d'autres moteurs fournissent des API VFS, donc quelque chose de similaire est possible. Et une fois implémenté, il devrait être compatible avec les structures de bases de données de toute complexité.

Maksee
la source
Selon vous, quelle est cette approche évolutive pour les grands projets?
matcauthon
Je pense que cela pourrait ajouter une surcharge de données importante pour les changements de données volumineuses (évidemment, car chaque modification doit être enregistrée, bien que la compression pour les anciennes versions puisse aider). En dehors de cela du point de vue de votre schéma, tant qu'il fonctionne pour deux tables, il fonctionne pour vingt.
Maksee
1

La méthode que nous utilisons pour versionner les entrées de la base de données consiste à utiliser une table d'audit. Le tableau a un schéma dans le sens 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

Nous avons alors des déclencheurs sur Insert / Update / Delete des tables que nous voulons suivre.

Avantages:

  • Toutes les données sont dans une seule table
  • Peut être configuré pour suivre tous les champs ou des champs spécifiques dans une table
  • Affichage facile des versions sur chaque champ d'une table

Les inconvénients:

  • Le fait d'avoir toutes les informations d'audit dans une seule table entraîne un très grand nombre d'enregistrements
  • Beaucoup de déclencheurs nécessaires
briddums
la source
0

J'en fais une version maintenant. pour chaque enregistrement, j'ai une date insérée, une date modifiée et un drapeau booléen d'enregistrement actif. Pour l'insertion initiale, les dates d'insertion et de modification sont toutes deux définies sur Now () (cet exemple se trouve dans Access) et l'indicateur d'enregistrement actif est défini sur true. puis si je modifie cet enregistrement, je copie le tout dans un nouvel enregistrement, en changeant le (s) champ (s) que l'utilisateur modifie, je laisse la date d'insertion égale à l'original et je change la date de modification en Now (). Je retourne ensuite l'indicateur d'enregistrement actif de l'enregistrement d'origine vers falseet le nouvel enregistrement vers true. J'ai également un champ pour ModifiedRecordsParentID où je sauvegarde l'identité de l'enregistrement d'origine.

Ensuite, si j'ai même besoin d'interroger, je peux simplement renvoyer les enregistrements où ActiveRecord = trueet je n'aurai que les informations les plus récentes.

Brad
la source
Pas besoin du ActiveRecorddrapeau. La ligne MAX (*) doit toujours être l'enregistrement en cours. La restauration d'une version précédente insère simplement à nouveau ladite ligne dans le tableau.
inverser le
Je ne savais pas comment faire fonctionner la sélection, mais maintenant que vous appelez cela, j'y pense et j'ai une idée, hmmmm
Brad
Généralement, MAX (nom_colonne) sélectionne la plus grande valeur dans la colonne du tableau. Pour sélectionner la ligne entière, un simple select top 1 order by id descendingsuffira.
inverser le
Oui, cela fonctionne pour un simple enregistrement unique, mais ma table était une collection d'enregistrements enfants qui devraient être sélectionnés en même temps mais auraient pu être modifiés individuellement. Un peu plus complexe.
Brad