Le migliori pratiche per la storia / le tabelle temporali?


11

Supponiamo di avere un oggetto, con alcuni campi in cui voglio tenere traccia della cronologia e determinati campi in cui non voglio tenere traccia della cronologia. Dal punto di vista della normalizzazione, va bene lo schema seguente:

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

dove MyObjectHistory contiene i campi monitorati per tutti tranne l'ultima revisione. Oppure, tutti i campi tracciati devono trovarsi in una tabella e tutte le revisioni incluse le ultime devono essere in quella tabella, come in:

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

Sono d'accordo con @Joel
HaBo il

Risposte:


7

Per motivi pratici di accesso ai dati, è necessario utilizzare la struttura dalla prima opzione, ma conservare invece tutte le versioni dei valori delle colonne monitorate, inclusa la versione corrente nella tabella della cronologia.

La ragione di ciò è che in generale, quando si desidera guardare la storia, si desidera includere la versione presente e tutte le versioni precedenti. Quando non vuoi guardare la storia, la vuoi fuori dai piedi. In molti casi questo significa arrivare al punto di separare la storia in uno schema o in un database completamente separati. Anche se mantieni la tua cronologia nello stesso schema dei tuoi dati attuali, qualsiasi query che guardi i dati storici (inclusi i valori correnti) sarà molto più complessa poiché devono fondamentalmente unire due fonti.


2

Preferirei la prima versione perché probabilmente hai solo raramente bisogno di vedere la cronologia ma spesso dovrai vedere il valore corrente. Una tabella di cronologia dovrebbe essere popolata da un trigger, quindi non è necessario preoccuparsi che i dati non vengano sincronizzati in generale. Supponiamo quindi di avere un milione di record in MyObject e quindi di avere 10.000.000 di record in MyObjectHistory. Vuoi davvero unirti a una tabella con così tanti record per ottenere il valore attuale?

Ora, se hai bisogno di interrogare la cronologia come frequentemente o più frequentemente del valore corrente, allora la seconda struttura funzionerebbe. (E se visualizzerai il valore a partire da una data particolare, avrei un campo begindate e enddate in esso per rendere più semplice l'interrogazione.)

A proposito, aggiungerei un campo data alla tabella della cronologia per essere in grado di dire in quale ordine sono avvenute le modifiche. Non puoi fare affidamento sulle identità per l'ordine temporale. Per favore, se c'è una domanda su un valore precedente e quando è cambiato, devi sapere. Potrei anche inserire i valori per l'applicazione da cui proviene la modifica (se si dispone di più applicazioni) e / o la persona che ha apportato la modifica.


0

Ci sono un paio di ragioni importanti per il n. 1. Il primo è il problema delle dimensioni che HLGEM sottolinea, ma ce ne sono anche altri importanti.

In genere, la traccia di audit avrà requisiti che si svilupperanno nel tempo. Potresti voler monitorare gli utenti del database, i tempi di modifica, ecc. È probabile che i requisiti della pista di controllo e la tabella principale cambino nel tempo in modo indipendente. Infine, è probabile che si desideri eliminare i dati della pista di controllo dopo un periodo di tempo in modo indipendente e una tabella completamente separata.

Naturalmente ci possono essere casi in cui si desidera unirli completamente (come facciamo per le aliquote fiscali in LedgerSMB) perché i dati storici possono essere utilizzati per i calcoli correnti e il numero di record è probabilmente relativamente piccolo.

Suggerirò, tuttavia, che la memorizzazione di oggetti in tabelle come questa raramente porta a buoni progetti normalizzati. Nella mia esperienza, vuoi davvero un po 'di incapsulamento tra una buona memoria normalizzata e un modello a oggetti di applicazione.


2
Cosa intendi con "incapsulamento tra una buona memoria normalizzata e un modello a oggetti applicazione"? Vuoi esporre su questa idea o fare un esempio?
cubetwo1729,
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.