Dans un projet sur lequel je travaille, chaque modification des lignes de certaines tables de la base de données doit être suivie pour un audit ou une restauration supplémentaire. Il doit être facile de trouver qui a modifié la ligne, à partir de quelle adresse IP et quand, et de pouvoir restaurer la version précédente.
La même chose est utilisée par exemple par Stack Exchange. Lorsque je modifie la question de quelqu'un d'autre, il est possible de constater que je l'ai modifiée et d'annuler les modifications.
Quelle est la technique générale utilisée pour stocker chaque modification d'un objet dans une base de données , étant donné que mon schéma actuel a essentiellement les mêmes propriétés (ci-dessous) qu'une application métier moyenne?
- Les objets ont une taille relativement petite: il peut y en avoir
nvarchar(1000)
par exemple, mais pas d'énormes blobs de données binaires, celui-ci étant stocké directement sur le disque et accessible directement, et non via Microsoft SQLfilestream
, - La charge de la base de données est assez faible et toute la base de données est gérée par une machine virtuelle sur un serveur,
- L'accès aux versions précédentes ne doit pas être aussi rapide que l'accès à la dernière version, mais doit toujours être à jour¹ et pas trop lent².
<tl-dr>
J'ai pensé aux cas suivants, mais je n'ai pas vraiment d'expérience avec ce genre de scénarios, donc j'entendrais les opinions des autres:
Stockez tout dans la même table, en distinguant les lignes par ID et version. OMI, c'est vraiment stupide, et ça fera mal tôt ou tard au niveau des performances. Avec cette approche, il est également impossible de définir un niveau de sécurité différent pour les derniers éléments et pour le suivi des versions. Enfin, chaque requête serait plus compliquée à écrire. En fait, pour accéder aux données à jour, je serais obligé de tout regrouper par ID et de récupérer, dans chaque groupe, la dernière version.
Stockez la dernière version dans une table et, à chaque modification, copiez la version obsolète dans une autre table dans un autre schéma. L'inconvénient est qu'à chaque fois, nous stockons chaque valeur, même si elle n'a pas changé. Définir des valeurs inchangées sur
null
n'est pas une solution, car je dois également suivre le moment où la valeur est modifiée versnull
ou depuisnull
.Stockez la dernière version dans une table et la liste des propriétés modifiées avec leurs valeurs précédentes dans une autre table. Cela semble avoir deux défauts: le plus important est que la seule façon de trier les types hétérogènes de valeurs précédentes dans la même colonne est d'avoir un
binary(max)
. La seconde est qu'il serait, je crois, plus difficile d'utiliser une telle structure lors de l'affichage des versions précédentes à l'utilisateur.Faites la même chose que dans deux points précédents, mais stockez les versions dans une base de données distincte. Côté performances, cela peut être intéressant pour éviter de ralentir l'accès aux dernières versions en ayant les versions précédentes dans la même base de données; Pourtant, je pense que c'est une optimisation prématurée et ne doit être effectuée que s'il existe une preuve que le fait d'avoir des versions plus anciennes et plus récentes dans la même base de données est un goulot d'étranglement.
</tl-dr>
¹ Par exemple, il serait inacceptable de stocker les modifications dans un fichier journal, comme c'est le cas pour les journaux HTTP, et de vider les données du journal dans la base de données la nuit lorsque la charge du serveur est la plus faible. Les informations sur les différentes versions doivent être disponibles immédiatement ou presque immédiatement; un délai de quelques secondes est acceptable.
² Les informations ne sont pas consultées très fréquemment et uniquement par un groupe spécifique d'utilisateurs, mais il serait tout de même inacceptable de les obliger à attendre 30 secondes que la liste des versions s'affiche. Encore une fois, un délai de quelques secondes est acceptable.