Conception de la base de données pour l'enregistrement des audits

chaque fois que j'ai besoin de créer une nouvelle base de données, je passe pas mal de temps je pense à la façon dont je devrais mettre en place le schéma de base de données pour tenir un journal d'audit de changement.

quelques questions ont déjà été posées ici à ce sujet, mais je ne suis pas d'accord que il y a une seule meilleure approche pour tous les scénarios:

j'ai également trébuché sur cet article intéressant sur la tenue d'un journal des changements de base de données qui tente d'énumérer les pour et les contre de chaque approche. Il est très bien écrit et contient des informations intéressantes, mais il a rendu mes décisions encore plus difficiles.

My la question Est: est-ce qu'il y a une référence que je peux utiliser, peut-être un livre ou quelque chose comme un arbre de décision que je peux me référer pour décider de quelle façon je dois aller basé sur certains variables d'entrée, comme:

  • La maturité du schéma de base de données
  • comment les logs seront interrogés
  • La probabilité qu'il sera nécessaire de recréer les dossiers
  • ce qui est plus important: écrire ou lire la performance
  • la Nature des valeurs qui sont enregistrées (chaîne de caractères, des nombres, des gouttes)
  • espace de stockage disponible

Les approches que je connais sont:

1. Ajouter les colonnes pour la date de création et de modification et l'utilisateur

exemple de tableau:

  • id
  • value_1
  • value_2
  • value_3
  • created_date
  • modifed_date
  • created_by
  • modifié par

principaux inconvénients: nous perdons l'histoire des modifications. Ne peut pas rollback après validation.

2. Insérer seulement les tableaux

exemple de tableau :

  • id
  • valeur_1
  • value_2
  • value_3
  • de
  • à
  • supprimé (booléen)
  • utilisateur

principaux inconvénients: comment garder les clés étrangères à jour?

3. Créer une table d'histoire séparée pour chaque table

exemple de table D'histoire:

  • id
  • value_1
  • value_2
  • value_3
  • value_4
  • utilisateur
  • supprimé (booléen)
  • timestamp

principaux inconvénients: il faut reproduire tous les tableaux vérifiés. Si le schéma change, il sera nécessaire de migrer tous les logs aussi.

4. Créer un Historique consolidé pour tous les tableaux

exemple de table D'histoire:

  • table_name
  • champ
  • utilisateur
  • new_value
  • supprimé (booléen)
  • timestamp

principaux inconvénients: vais-je être en mesure de recréer les enregistrements (retour en arrière) si nécessaire facilement? La colonne new_value doit être énorme string pour qu'il puisse supporter tous les différents types de colonnes.

125
demandé sur Community 2010-01-06 21:27:40

5 réponses

une méthode qui est utilisée par quelques plateformes wiki est de séparer les données d'identification et le contenu que vous auditez. Cela ajoute de la complexité, mais vous vous retrouvez avec une piste d'audit d'enregistrements complets, pas seulement des listes de champs qui ont été édités que vous devez ensuite masquer pour donner à l'utilisateur une idée de ce à quoi ressemblait l'ancien enregistrement.

donc, par exemple, si vous aviez un tableau appelé opportunités pour suivre les offres de vente, vous auriez en fait créer deux tableaux séparés:

opportunités

Opportunitys_content (ou quelque chose comme ça)

la table Opportunities aurait l'information que vous utiliseriez pour identifier de façon unique le document et contiendrait la clé primaire que vous utiliseriez comme référence pour vos relations avec des clés étrangères. La table Opportunities_Content contiendrait tous les les champs de vos utilisateurs peuvent changer et pour lequel vous souhaitez conserver une piste de vérification. Chaque enregistrement dans la table Content inclurait son propre PK ainsi que les données de date de péremption et de date de péremption. Le tableau Opportunities inclurait une référence à la version actuelle ainsi que des informations sur la date de création du document principal et par qui.

voici un exemple simple:

CREATE TABLE dbo.Page(  
    ID int PRIMARY KEY,  
    Name nvarchar(200) NOT NULL,  
    CreatedByName nvarchar(100) NOT NULL, 
    CurrentRevision int NOT NULL, 
    CreatedDateTime datetime NOT NULL

et le sommaire:

CREATE TABLE dbo.PageContent(
    PageID int NOT NULL,
    Revision int NOT NULL,
    Title nvarchar(200) NOT NULL,
    User nvarchar(100) NOT NULL,
    LastModified datetime NOT NULL,
    Comment nvarchar(300) NULL,
    Content nvarchar(max) NOT NULL,
    Description nvarchar(200) NULL

je ferais probablement du PK de la table des matières une clé multi-colonnes à partir de la PageID et de la révision à condition que la révision soit un type d'identité. Vous utiliserez la colonne de révision comme FK. Vous tirez alors le dossier consolidé en joignant comme ceci:

SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID

il pourrait y avoir des erreurs là-haut...c'est hors de ma tête. Il devrait vous donner une idée d'un autre modèle.

Josh

78
répondu Josh Anderson 2016-01-21 19:18:48

si vous utilisez SQL Server 2008, vous devriez probablement envisager de modifier la Capture de données. Ceci est nouveau pour 2008 et pourrait vous épargner beaucoup de travail.

11
répondu Randy Minder 2010-01-06 18:47:01

Je ne connais aucune référence, mais je suis sûr que quelqu'un a écrit quelque chose.

cependant, si le but est simplement d'avoir un enregistrement de ce qui s'est passé-l'utilisation la plus typique d'un journal de vérification-alors pourquoi ne pas simplement tout garder:

timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue

probablement maintenu par un déclencheur.

6
répondu wallyk 2010-01-06 18:34:13

je pense qu'il n'y a rien comme un arbre de décision. Car certains avantages et inconvénients (ou les exigences) ne sont pas vraiment dénombrables. Comment mesurer la Maturité, par exemple?

donc, alignez vos besoins d'affaires pour votre enregistrement de vérification. Essayez de prédire comment ces exigences pourraient changer à l'avenir et générer vos exigences techniques. Maintenant vous pouvez comparer les avantages et les inconvénients et de choisir la bonne/meilleure option.

et be peu importe comment vous décidez, il y aura toujours quelqu'un qui pensera que vous avez pris la mauvaise décision. Cependant, vous avez fait vos devoirs et vous justifiez votre décision.

3
répondu Peter Schuetze 2010-01-06 18:47:56

nous allons créer un petit exemple de base de données pour une application de blogging. Deux tableaux sont requis:

blog : stocke un ID de poste unique, le titre, le contenu, et un drapeau supprimé. audit : stocke un ensemble de base de changements historiques avec un enregistrement ID, le blog post ID, le type de changement (Nouveau, modifier ou supprimer) et la date/heure de ce changement. Le SQL suivant crée le blog et indexe la colonne supprimée:

CREATE TABLE `blog` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `title` text,
    `content` text,
    `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `ix_deleted` (`deleted`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Blog posts';

le le SQL suivant crée la table audit . Toutes les colonnes sont indexées et une clé étrangère est définie pour vérification.blog_id which references blog.id. Par conséquent, lorsque nous supprimons physiquement une entrée de blog, son historique complet d'audit est également supprimé.

CREATE TABLE `audit` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `blog_id` mediumint(8) unsigned NOT NULL,
    `changetype` enum('NEW','EDIT','DELETE') NOT NULL,
    `changetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `ix_blog_id` (`blog_id`),
    KEY `ix_changetype` (`changetype`),
    KEY `ix_changetime` (`changetime`),
    CONSTRAINT `FK_audit_blog_id` FOREIGN KEY (`blog_id`) REFERENCES `blog` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2
répondu ajit 2015-04-24 05:51:37