Progettazione del database per la registrazione di controllo


151

Ogni volta che devo progettare un nuovo database, passo un po 'di tempo a pensare a come impostare lo schema del database per tenere un registro di controllo delle modifiche.

Alcune domande sono già state poste qui a riguardo, ma non sono d'accordo sul fatto che esista un unico approccio migliore per tutti gli scenari:

Mi sono anche imbattuto in questo interessante articolo sul mantenimento di un registro delle modifiche al database che tenta di elencare i pro e i contro di ogni approccio. È scritto molto bene e ha informazioni interessanti, ma ha reso le mie decisioni ancora più difficili.

La mia domanda è: c'è un riferimento che posso usare, forse un libro o qualcosa come un albero decisionale a cui posso fare riferimento per decidere in che modo devo andare basato su alcune variabili di input, come:

  • La maturità dello schema del database
  • Come verranno interrogati i registri
  • La probabilità che sarà necessario ricreare i record
  • Cosa c'è di più importante: scrivere o leggere le prestazioni
  • Natura dei valori che vengono registrati (stringa, numeri, BLOB)
  • Spazio di archiviazione disponibile

Gli approcci che conosco sono:

1. Aggiungi colonne per data e utente creati e modificati

Esempio di tabella:

  • id
  • value_1
  • value_2
  • VALUE_3
  • Data di Creazione
  • data modificata
  • creato da
  • modificato da

Svantaggi principali: perdiamo la cronologia delle modifiche. Impossibile eseguire il rollback dopo il commit.

2. Inserisci solo tabelle

Esempio di tabella :

  • id
  • value_1
  • value_2
  • VALUE_3
  • a partire dal
  • per
  • cancellato (booleano)
  • utente

Principali svantaggi: come mantenere aggiornate le chiavi esterne? Enorme spazio necessario

3. Creare una tabella di cronologia separata per ogni tabella

Esempio di tabella cronologica:

  • id
  • value_1
  • value_2
  • VALUE_3
  • VALUE_4
  • utente
  • cancellato (booleano)
  • timestamp

Svantaggi principali: è necessario duplicare tutte le tabelle controllate. Se lo schema cambia, sarà necessario migrare anche tutti i registri.

4. Creare una tabella di cronologia consolidata per tutte le tabelle

Esempio di tabella cronologica:

  • table_name
  • campo
  • utente
  • NEW_VALUE
  • cancellato (booleano)
  • timestamp

Svantaggi principali: Sarò in grado di ricreare i record (rollback) se necessario facilmente? La colonna new_value deve essere una stringa enorme in modo che possa supportare tutti i diversi tipi di colonna.



1
e che dire dell'utilizzo di un database cronologico anziché delle tabelle?
Jowen,

Forse potresti controllare il design di github.com/airblade/paper_trail
zx1986

È una cattiva idea registrare tutte le query (obbligatorie) eseguite così com'è?
Dinushan,

Risposte:


87

Un metodo utilizzato da alcune piattaforme wiki è quello di separare i dati identificativi e il contenuto che stai controllando. Aggiunge complessità, ma si finisce con una pista di controllo di record completi, non solo elenchi di campi che sono stati modificati che è quindi necessario combinare per dare all'utente un'idea di come fosse il vecchio record.

Ad esempio, se avessi una tabella chiamata Opportunità per tenere traccia delle offerte di vendita, in realtà creeresti due tabelle separate:

Opportunities
Opportunities_Content (o qualcosa del genere)

La tabella Opportunità contiene le informazioni che useresti per identificare in modo univoco il record e ospiterebbe la chiave primaria a cui faresti riferimento per le relazioni con le chiavi esterne. La tabella Opportunities_Content conterrebbe tutti i campi che i tuoi utenti possono modificare e per i quali desideri conservare una traccia di controllo. Ogni record nella tabella Contenuto includerebbe il proprio PK e i dati di data e data di modifica. La tabella Opportunità includerebbe un riferimento alla versione corrente nonché informazioni su quando il record principale è stato originariamente creato e da chi.

Ecco un semplice esempio:

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

E i contenuti:

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

Probabilmente farei del PK della tabella dei contenuti una chiave multi-colonna di PageID e Revision a condizione che Revision fosse un tipo di identità. Dovresti usare la colonna Revision come FK. Quindi si estrae il record consolidato ENTRANDO in questo modo:

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

Potrebbero esserci degli errori lassù ... questo è fuori dalla mia testa. Tuttavia, dovrebbe darti un'idea di un modello alternativo.


10
In termini di buon approccio alla revisione, ma per la produzione ci vorrà molto tempo per sviluppare una tabella di verifica separata per ogni tabella nel database, scrivere i trigger per ogni tabella per acquisire le modifiche e scriverla nella tabella di controllo. Inoltre, un'enorme sfida nello sviluppo di un unico rapporto di audit per tutte le tabelle poiché ciascuna tabella di audit ha una struttura diversa.
asim-ishaq,

11
Se la scrittura e la gestione di script per ogni tabella è un problema per un'organizzazione che intende gestire un database verificato, consiglierei naturalmente di assumere un DBA esperto o un ingegnere informatico altamente flessibile e di grande esperienza con adeguata esperienza nella creazione di database controllati .
Hardryv

1
È corretto che PageContent.PageIDsia FK Page.IDe Page.CurrentRevisionFK PageContent.Revision? Questa dipendenza è davvero circolare?

2
Ho votato in giù poiché non affronta le alternative menzionate. Dà un'altra opzione che è una soluzione molto specifica per un caso d'uso molto specifico. Ma vedo i meriti del design suggerito
Atteon

1
Riesco a pensare a pochissimi campi che potrei dire con sicurezza non cambieranno, quindi tutte le tabelle "principali" per ogni entità finiranno per essere id, revision_id; più di un tavolo di giunzione, davvero. Mi sembra un po 'maleodorante. Che vantaggio ha questo rispetto all'approccio 3 in OP (tabella di cronologia per tabella controllata)?
Kenmore

14

Se stai usando SQL Server 2008, probabilmente dovresti considerare Change Data Capture. Questo è nuovo per il 2008 e potrebbe farti risparmiare una notevole quantità di lavoro.


ecco il link alle informazioni di tracciamento delle modifiche di SQL 2012. msdn.microsoft.com/en-us/library/bb933994.aspx +1 per l'utilizzo della funzionalità integrata, inutile reinventare la ruota.
Chris,

4
@ Chris l'hai mai usato da solo? In effetti, tiene traccia di tutto ... ma essere in grado di ricavarne informazioni utili è tutta un'altra storia. Non riesco a usare una ruota del trattore per la mia bici.
Jowen,

Sarebbe stato davvero fantastico. Ma se hai solo l' edizione standard di SQL Server, come me, sei sfortunato: "L'acquisizione dei dati di modifica è disponibile solo nelle edizioni Enterprise , Developer ed Enterprise Evaluation ".
Brad Turek,

6

Non conosco alcun riferimento, ma sono sicuro che qualcuno abbia scritto qualcosa.

Tuttavia, se lo scopo è semplicemente quello di tenere traccia di ciò che è accaduto, l'uso più tipico di un registro di controllo, allora perché non conservare semplicemente tutto:

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

Presumibilmente, questo è gestito da un trigger.


Non conosco alcun modo per farlo all'interno del server di database, ma ovviamente ciò potrebbe essere fatto dall'esterno abbastanza facilmente.
Wallyk,

5
Mi sembra che questo sia lo stesso modello di design della quarta opzione mostrata nella domanda originale.
givanse,

3

Creeremo un piccolo database di esempio per un'applicazione di blog. Sono necessarie due tabelle:

blog: memorizza un ID post univoco, il titolo, il contenuto e un flag eliminato. audit: memorizza un set di base di modifiche storiche con un ID record, l'ID del post sul blog, il tipo di modifica (NUOVO, MODIFICA o ELIMINA) e la data / ora della modifica. Il seguente SQL crea bloge indicizza la colonna eliminata:

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';

Il seguente SQL crea la audittabella. Tutte le colonne sono indicizzate e viene definita una chiave esterna per audit.blog_id che fa riferimento a blog.id. Pertanto, quando ELIMINIAMO fisicamente un post di blog, viene rimossa anche la cronologia di controllo completa.

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

Penso che non ci sia niente come un albero decisionale. Dal momento che alcuni dei pro e contro (o dei requisiti) non sono veramente contabili. Come misurate la maturità per esempio?

Quindi, basta allineare i requisiti aziendali per la registrazione di controllo. Prova a prevedere in che modo questi requisiti potrebbero cambiare in futuro e generare i tuoi requisiti tecnici. Ora puoi confrontarlo con pro e contro e scegliere l'opzione giusta / migliore.

E assicurati, non importa come decidi, ci sarà sempre qualcuno che pensa che tu abbia preso la decisione sbagliata. Tuttavia, hai fatto i compiti e giustifichi la tua decisione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.