2009-04-06 1 views
18

Come progettare un database che supporta una funzionalità che consentirebbe all'utente dell'applicazione di creare un'istantanea dei propri dati in un determinato momento, un po 'come il controllo della versione.Progettazione del database per lo "snapshot" temporale dei dati?

Darebbe all'utente la possibilità di tornare indietro e vedere come erano i dati in passato.

Si supponga che i dati "snapshot" siano complessi e includano join di più tabelle.

Sto cercando un modo per dare ad ogni utente dell'applicazione la possibilità di eseguire un'istantanea dei dati e tornare ad essa. Intere snapshot di database non sono quello che sto cercando.

EDIT: Grazie per le vostre risposte. La risposta 6NF è convincente come il suggerimento di de-normalizzare i dati dell'istantanea grazie alla sua semplicità.

Precisazione: non si tratta di una domanda di data warehousing né di un backup e di un ripristino DB; si tratta di come costruire uno schema che ci permetta di catturare lo stato di una serie specifica di dati correlati in un determinato momento. Le istantanee vengono generate dagli utenti dell'applicazione quando lo ritengono opportuno. Gli utenti non snapshot l'intero DB, solo l'oggetto di dati sono interessati.

+0

SQL Server 2005 o 2008. Tuttavia, se c'è un altro RDBMS con una soluzione integrata per questo tipo di problema, sarei interessato a sentirlo. Thx – saille

risposta

9

L'abbiamo fatto una volta con la creazione di tabelle di database separati che contengono i dati che volevamo snapshot, ma denormalizzato, vale a dire ogni record contiene tutti i dati necessari per dare un senso, non i riferimenti a id che esistono può o non più. Inoltre ha aggiunto una data a ciascuna riga.

Quindi abbiamo generato trigger per inserti o aggiornamenti specifici che hanno eseguito un join su tutte le tabelle interessate e inserito nelle tabelle degli snapshot.

In questo modo sarebbe banale scrivere qualcosa che ripristini i dati degli utenti in un determinato momento.

Se si dispone di una tabella:

utente:

id, firstname, lastname, department_id 

reparto:

id, name, departmenthead_id 

l'istantanea della tabella utente potrebbe assomigliare a questo:

user_id, user_firstname, user_lastname, department_id, department_name, deparmenthead_id, deparmenthead_firstname, departmenthead_lastname, snapshot_date 

e una query qualcosa l ike

INSERT INTO usersnapshot 
SELECT user.id AS user_id, user.firstname AS user_firstname, user.lastname AS user_lastname, 
department.id AS department_id, department.name AS department_name 
departmenthead.id AS departmenthead_id, departmenthead.firstname AS departmenthead_firstname, departmenthead.lastname AS departmenthead_lastname, 
GETDATE() AS snapshot_date 
FROM user 
INNER JOIN department ON user.department_id = department.id 
INNER JOIN user departmenthead ON department.departmenthead_id = departmenthead.id 

Questo assicura ogni riga l'istantanea è vero per quel momento, anche se dipartimento o reparto testa è cambiato nel frattempo.

0

SQL Server 2005 (poi) Enterprise Edition ha la capacità di creare Database snapshots

0

Oracle dalla versione 9i avere la tecnologia Flashback, che è in Oracle 10g e 11g sono molto migliorati e puoi vedere lo stato del tuo database in qualsiasi punto della storia, purché tu abiliti il ​​flashback.

Controllare questo documento: Flashback Overview

0

È possibile utilizzare i log prodotti dal RDBMS per ottenere istantanee dei dati. Normalmente i log vengono utilizzati per fornire il ripristino del database. Possono tuttavia essere utilizzati anche per replicare i dati su più istanze RDBMS o per ottenere istantanee dei dati.

Per ottenere un'istantanea dei dati, è sufficiente prendere in considerazione tutti i registri prodotti prima del momento desiderato. Quindi "riproduci" quei log per ottenere il database effettivo con i dati ripristinati.

Come accedere e "riprodurre" i registri dipende dal prodotto RDBMS concreto utilizzato.

Un'altra possibilità è utilizzare i database temporali. Hanno aspetti del tempo integrati e consentono di "tornare indietro nel tempo". Cerca "Oracle Flashback Technology" per esempio. http://www.stanford.edu/dept/itss/docs/oracle/10g/appdev.101/b10795/adfns_fl.htm#ADFNS1008

17

Questo NON è facile.

Stai essenzialmente richiedendo un database temporale (che Christopher Date chiama Sixth Normal Form o 6NF).

Per essere 6NF, uno schema deve anche essere 5NF, e, in sostanza, per ogni dato, è necessario collegare un intervallo di tempo per il quale è applicabile il dato a quel valore. Quindi, in join, il join deve includere solo le righe che si trovano nell'intervallo di tempo considerato.

La modellazione temporale è difficile - è ciò che è il sesto indirizzo di forma normale - e non è ben supportata negli attuali RDBMS.

Il problema è la granularità. La sesta forma normale (a quanto ho capito) supporta la modellazione temporale rendendo ogni non chiave (non-chiave :, cioè, qualsiasi cosa "su" l'entità che può cambiare senza che l'entità perda la sua identità) una relazione separata. A questo, aggiungi un timestamp o un intervallo di tempo o un numero di versione. Rendere tutto un join risolve il problema della granularità, ma significa anche che le tue query saranno più complicate e lente. Richiede anche di capire tutte le chiavi e gli attributi non chiave; questo tende ad essere un grande sforzo.

In sostanza, ovunque si ha una relazione ("ted possiede il titolo azionario GM con id 789") si aggiunge un tempo: "ted possiede il titolo azionario GM con id 789 ora" in modo che si può dire contemporaneamente, "Fred possiede il certificato azionario GM con ID 789 dal 3 febbraio 2000 a ieri". Ovviamente queste relazioni sono molte-a-molti, (Ted può possedere più di un certificato ora, e anche più di uno nel corso della sua vita, e fred può avere in precedenza posseduto il jack del certificato proprio ora).

Quindi abbiamo una tabella di proprietari e una tabella di certificati azionari e una tabella molti-a-molti che mette in relazione proprietari e certificati con id. Alla tabella many-to-many, aggiungiamo un start_date e un end_date.

Ora, immagina che ogni stato/provincia/terra riscuota i dividendi sui certificati azionari, quindi a fini fiscali per registrare lo stato di residenza del proprietario del certificato azionario.

Dove risiede il proprietario può ovviamente cambiare in modo indipendente con la proprietà delle azioni; Ted può vivere in Nebraska, comprare 10 azioni, ottenere un dividendo che le tasse del Nebraska, trasferirsi in Nevada, vendere 5 azioni a Fred, comprare altre 10 azioni.

Ma per noi, è Ted può muoversi in Nebraska a un certo momento, acquistare 10 azioni a un certo momento, ottenere un dividendo a un certo momento, quali tasse Nebraska, passare a Neveda a un certo momento , vendere 5 azioni a fred a un certo momento, acquistare altre 10 azioni a un certo momento.

Abbiamo bisogno di tutto questo se vogliamo calcolare le tasse dovute in Nebraska e in Nevada, unendo gli intervalli di date corrispondenti/sovrapposti in person_stockcertificate e person_address. L'indirizzo di una persona non è più one-to-one, è uno-a-molti perché è l'indirizzo nell'intervallo di tempo.

Se ted acquista dieci azioni, modelliamo un evento di acquisto con un'unica data di acquisto o aggiungiamo una data_bought a ogni condivisione? Dipende dalla domanda a cui il modello deve rispondere.

+1

Una soluzione generica è sicuramente difficile da realizzare, ma per un caso d'uso e un sottoinsieme di dati specifici sufficienti, una soluzione come quella descritta potrebbe essere accettabile. –

0

Con SQL Server almeno, è possibile utilizzare la registrazione completa e mantenere i registri delle transazioni tra ciascun set di backup.

Quindi è possibile eseguire un backup temporizzato.

Questa è una soluzione scadente.

Che cosa desidera esattamente il cliente? È per scopi analitici (cioè le domande sono come quanti ordini abbiamo avuto due settimane fa)? Perché questo è esattamente il problema che risolve un datawarehouse.

1

Avere snapshot e/o un audit trail è un requisito di database comune. Per molte applicazioni, la creazione di 'shadow' o tabelle di controllo è un'attività semplice e immediata. Sebbene i backup a livello di database e i registri delle transazioni siano validi, non sono un sistema di controllo della versione.

Fondamentalmente, è necessario creare una tabella shadow con tutte le stesse colonne della tabella di base e quindi impostare i trigger sulla tabella di base per posizionare una copia della riga nella tabella shadow ogni volta che viene aggiornata o eliminata.

Attraverso una certa logica è possibile ricreare l'aspetto dei dati in un dato momento. Per un modo semplice per impostare questo in Sybase, vedere: http://www.theeggeadventure.com/wikimedia/index.php/Sybase_Tips#create_.27audit.27_columns

Se è necessario eseguire molte istantanee cronologiche, è possibile mantenere i dati nella stessa tabella. Fondamentalmente, crea due colonne: una colonna aggiunta ed eliminata. Lo svantaggio è per ogni query è necessario aggiungere una clausola where. Ovviamente puoi creare una vista, che mostra solo i record attivi. Questo diventa un po 'più complicato se si dispone di un database normalizzato con più tabelle, tutte con cronologia.

Tuttavia, funziona. Hai semplicemente le colonne "aggiunte" e "cancellate" su ogni tabella, e quindi la tua query ha il punto nel tempo di interesse. Ogni volta che i dati vengono modificati, è necessario copiare la riga corrente e contrassegnarla come eliminata.

1

Usa Log Triggers

Tutti i dati vengono catturati cambiamenti, dando la possibilità di interrogare come se in qualsiasi punto nel tempo.

0

Forse prendere in considerazione l'utilizzo di una soluzione NoSql come MongoDB per aggregare tutti i dati relazionali in un unico documento, quindi archiviare tale documento con un timestamp o un numero di versione. Soluzioni come Kafka-Connect o Oracle Golden Gate semplificano la trasmissione dei dati relazionali nei negozi NoSql.