Favorire l'immutabilità nella progettazione di database

26

Uno degli elementi di Java efficace di Joshua Bloch è la nozione secondo cui le classi dovrebbero consentire la mutazione delle istanze il meno possibile, e preferibilmente non del tutto.

Spesso, i dati di un oggetto sono persistenti in un database di qualche forma. Questo mi ha portato a pensare all'immutabilità all'interno di un database, specialmente per quelle tabelle che rappresentano una singola entità all'interno di un sistema più grande.

Qualcosa su cui ho sperimentato di recente è l'idea di provare a ridurre al minimo gli aggiornamenti che faccio alle righe della tabella che rappresentano questi oggetti, e cercando di eseguire gli inserimenti invece che posso.

Un esempio concreto di qualcosa che stavo sperimentando di recente. Se so che potrei aggiungere un record con dati aggiuntivi in seguito, creerò un'altra tabella per rappresentarla, un po 'come le seguenti due definizioni di tabella:

create table myObj (id integer, ...other_data... not null);
create table myObjSuppliment (id integer, myObjId integer, ...more_data... not null);

È auspicabile che questi nomi non siano verbali, ma solo per dimostrare l'idea.

Si tratta di un approccio ragionevole alla modellizzazione della persistenza dei dati? Vale la pena provare a limitare gli aggiornamenti eseguiti su una tabella, in particolare per il riempimento di valori null per i dati che potrebbero non esistere quando il record è stato creato in origine? Ci sono momenti in cui un approccio come questo potrebbe causare un strong dolore in seguito?

    
posta Ed Carrel 05.09.2011 - 02:23
fonte

8 risposte

25

Lo scopo principale dell'immutabilità è garantire che non ci sia un istante nel tempo in cui i dati in memoria si trovano in uno stato non valido. (L'altro è perché le notazioni matematiche sono per lo più statiche e le cose così immutabili sono più facili da concettualizzare e modellare matematicamente.) In memoria, se un altro thread tenta di leggere o scrivere dati mentre viene lavorato, potrebbe finire per essere corrotto, o potrebbe essere esso stesso in uno stato corrotto. Se disponi di più operazioni di assegnazione ai campi di un oggetto, in un'applicazione multithread, un altro thread potrebbe provare a lavorarci in un momento intermedio, il che potrebbe essere negativo.

L'immutabilità risolve questo problema scrivendo dapprima tutti i cambiamenti in un nuovo posto in memoria, e poi facendo l'ultimo compito come un passo in picchiata per riscrivere il puntatore sull'oggetto per puntare al nuovo oggetto - che su tutte le CPU è un'operazione atomica .

Le banche dati fanno la stessa cosa usando transazioni atomiche : quando si avvia una transazione, scrive tutti i nuovi aggiornamenti in un nuovo posto sul disco. Quando finisci la transazione, cambia il puntatore sul disco dove sono i nuovi aggiornamenti, cosa che fa in un breve istante durante il quale altri processi non possono toccarlo.

Questa è anche la stessa cosa della tua idea di creare nuove tabelle, eccetto quelle più automatiche e più flessibili.

Quindi per rispondere alla tua domanda, sì, l'immutabilità è buona nei database, ma no, non è necessario creare tabelle separate solo per quello scopo; puoi semplicemente utilizzare qualsiasi comando di transazione atomica disponibile per il tuo sistema di database.

    
risposta data 05.09.2011 - 04:52
fonte
23

Dipende da quali benefici ti aspetti di ottenere dall'immutabilità. La risposta di Rei Miyasaka è rivolta a uno (evitamento di stati intermedi non validi), ma ecco un altro.

Talvolta la mutazione viene chiamata aggiornamento distruttivo : quando si muta un oggetto, il vecchio stato viene perso (a meno che non si adottino ulteriori passaggi per conservarlo in qualche modo in modo esplicito). Al contrario, con dati immutabili, è banale rappresentare simultaneamente lo stato sia prima che dopo un'operazione, o rappresentare più stati successori. Immagina di provare a implementare una ricerca in ampiezza mutando un singolo oggetto di stato.

Questo probabilmente si presenta nel mondo del database più spesso come dati temporali . Dì che il mese scorso eri sul piano di base, ma il 16 sei passato al piano Premium. Se abbiamo appena sovrascritto un campo che indicava il piano in cui ti trovi, potremmo avere difficoltà a ottenere la fatturazione giusta. Potremmo anche perdere la capacità di analizzare le tendenze. (Ehi, guarda cosa ha fatto questa campagna pubblicitaria locale!)

Questo è ciò che mi viene in mente quando dici "immutabilità nella progettazione del database", comunque.

    
risposta data 05.09.2011 - 10:01
fonte
14

Se sei interessato ai benefici che puoi ottenere dall'immutabilità in un database, o almeno un database che offre l'illusione dell'immutabilità, controlla Datomic.

Datomic è un database inventato da Rich Hickey in alleanza con Think Relevance, ci sono molti video in cui spiegano l'architettura, gli obiettivi, il modello dei dati. Cerca infoq, uno in particolare è intitolato Datomic, Database come valore . In confreak potete trovare un keynote che Rich Hickey ha dato alla conferenza euroclojure nel 2012. confreaks.com/videos/2077-euroclojure2012-day-2-keynote-the-datomic-architecture-and-data-model

C'è un discorso in vimeo.com/53162418 che è più orientato allo sviluppo.

Ecco un altro da stuart halloway at.pscdn.net/008/00102/videoplatform/kv/121105techconf_close.html

  • Datomic è un database di fatti nel tempo, chiamati datum, in 5-tuple [E, A, V, T, O]
    • E ID entità
    • A Nome attributo nell'entità (può avere spazi dei nomi)
    • V Valore dell'attributo
    • T ID transazione, con questo hai una nozione di tempo.
    • O Un'operazione di asserzione (valore presente o corrente), rifiuto (valore passato);
  • Utilizza il proprio formato dati, denominato EDN (Extensible Data Notation)
  • Le transazioni sono ACID
  • Utilizza il registro dei dati come linguaggio di query, che è dichiarativo come SQL + domande ricorsive. Le query sono rappresentate con strutture dati ed estese con il tuo linguaggio jvm, non è necessario usare clojure.
  • Il database è disaccoppiato in 3 servizi separati (processi, macchine):
    • transazione
    • archiviazione
    • Motore di query.
  • Puoi separatamente, ridimensionare ogni servizio.
  • Non è open source, ma c'è la versione gratuita (come nella birra) di Datomic.
  • Puoi indicare uno schema flessibile.
    • set di attributi è aperto
    • aggiungi nuovi attributi in qualsiasi momento
    • nessuna rigidità nella definizione o nella query

Ora, dato che le informazioni sono archiviate come fatti nel tempo:

  • tutto ciò che fai è aggiungere fatti al database, non eliminarli mai (tranne quando è richiesto dalla legge)
  • puoi memorizzare tutto per sempre. Motore di query, risiede nel server delle applicazioni come un database in memoria (per le lingue jvm le lingue non jvm possono accedere tramite un'API REST).
  • puoi eseguire una query a partire dal passato.

Il database è un valore e un parametro per il motore di query, il QE gestisce la connessione e la memorizzazione nella cache. Poiché è possibile vedere il db come un valore e una struttura di dati immutabile nella memoria, è possibile unirlo con un'altra struttura dati composta da valori "in futuro" e passarla al QE & eseguire una query con valori futuri, senza modificare il database effettivo.

C'è un progetto open source da Rich Hickey, chiamato codeq , puoi trovarlo in github Datomic / codeq, che estende il modello git e memorizza i riferimenti agli oggetti git in un datomic-free database, e fai query sul tuo codice, puoi vedere un esempio di come usare datomic.

Puoi pensare a datomic come un NoSQL ACID, con i datum puoi modellare tabelle o documenti o Kv-stores o grafici.

    
risposta data 02.06.2013 - 21:55
fonte
7

L'idea di evitare gli aggiornamenti e di preferire gli inserti è uno dei pensieri alla base della creazione dell'archiviazione dei dati come sorgente di eventi, un'idea che troverai spesso utilizzata insieme a CQRS. In un modello di origine evento, non vi è alcun aggiornamento: un aggregato è rappresentato come la sequenza della sua "trasformazione" (eventi) e, di conseguenza, lo spazio di archiviazione è solo append.
Questo sito contiene interessanti discussioni su CQRS e l'approvvigionamento di eventi, se sei curioso di farlo!

    
risposta data 05.09.2011 - 22:31
fonte
6

Ciò comporta una relazione molto stretta con le cosiddette "dimensioni che cambiano lentamente" nel mondo del data warehousing e le tabelle "Temporal" o "Bi-Temporal" in altri domini.

Il costrutto di base è:

  1. Utilizza sempre una chiave surrogata generata come chiave primaria.
  2. L'identificatore univoco di qualsiasi cosa tu stia descrivendo diventa la "chiave logica".
  3. Ogni riga deve avere almeno un timestamp "ValidFrom" e opzionalmente un timestamp "ValidTo" e anche più facoltativamente un flag "Ultima versione".
  4. Sulla "creazione" di un'entità logica, inserisci una nuova riga con un "Valido da" del timestamp corrente. ValidTo facoltativo impostato su "per sempre" (9999-12-31 23:59:59) e Ultima versione su "Vero".
  5. In un successivo aggiornamento dell'entità logica. Almeno inserisci una nuova riga come sopra. Potrebbe anche essere necessario regolare ValidTo sulla versione precedente su "now () - 1 secondo" e l'ultima versione su "False"
    1. Durante l'eliminazione logica (funziona solo con il timestamp ValidTo!) imposti il flag ValidTo nella riga corrente su "now () -1 secondi".

I vantaggi di questo schema è che puoi ricreare lo "stato" della tua entità logica in qualsiasi momento, hai una storia della tua entità nel tempo e riduci al minimo la contesa se la tua "entità logica" è strongmente utilizzata.

Gli svantaggi sono la memorizzazione di molti più dati e devi mantenere più indici (almeno su Logical Key + ValidFrom + ValidTo). Un indice su Logical Key + Ultima versione accelera notevolmente la maggior parte delle query. Inoltre complica il tuo SQL!

Spetta a te decidere se vale la pena farlo, a meno che tu non abbia davvero bisogno di mantenere una cronologia e avere la necessità di ricreare lo stato delle tue entità in un dato momento.     

risposta data 12.10.2011 - 06:32
fonte
1

Un altro motivo possibile per avere un database immutabile sarebbe quello di supportare una migliore elaborazione parallela. Gli aggiornamenti che si verificano in modo non funzionante possono compromettere i dati in modo permanente, pertanto è necessario eseguire il blocco per impedirlo, distruggendo le prestazioni parallele. Un sacco di inserimenti di eventi può andare in qualsiasi ordine, e lo stato sarà almeno alla fine giusto finché tutti gli eventi saranno elaborati. Tuttavia, in pratica è così difficile lavorare con gli aggiornamenti del database che si dovrebbe davvero avere bisogno di molto parallelismo per considerare di fare le cose in questo modo - io sono non lo consiglio.

    
risposta data 11.10.2011 - 22:45
fonte
0

Dichiarazione di non responsabilità: sono praticamente una novità in DB: p

Detto questo, questo approccio ai dati di satelliti ha un impatto immediato sulle prestazioni:

  • Buono meno traffico sulla tabella principale
  • Buone righe più piccole nella tabella principale
  • Cattivo che richiede i dati satellitari significa che è necessaria un'altra ricerca
  • Cattivo più spazio occupato se tutti gli oggetti esistono in entrambe le tabelle

a seconda delle tue esigenze, puoi accettarlo o meno, ma è certamente un punto da considerare.

    
risposta data 05.09.2011 - 19:55
fonte
-1

Non vedo come il tuo schema possa essere definito "immutabile".

Cosa succede quando un valore memorizzato nella tabella supplementare cambia? Sembra che tu debba eseguire un aggiornamento su quel tavolo.

Affinché un database sia veramente immutabile, dovrebbe essere mantenuto esclusivamente da "INSERTS". Per questo è necessario un metodo per identificare la riga "corrente". Questo quasi sempre finisce per essere orribilmente inefficiente. È necessario copiare tutti i precedenti valori invariati o, insieme, raggruppare lo stato corrente da diversi record quando si esegue una query. La selezione della riga corrente di solito richiede un po 'di SQL orribilmente disordinato ( where updTime = (SELECT max(updTime) from myTab where id = ? ).

Questo problema si presenta molto in DataWarehousing in cui è necessario mantenere una cronologia dei dati nel tempo e, essere in grado di selezionare lo stato per un dato punto nel tempo. La soluzione è solitamente tabelle "dimensionali". Tuttavia mentre risolvono il problema DW "chi era il rappresentante delle vendite lo scorso gennaio". Non forniscono nessuno dei vantaggi che fanno le classi immutabili di Javas.

Su una nota più filosofica; esistono database per memorizzare "stato" (il tuo conto in banca, il tuo consumo di elettricità, i tuoi punti brownie su StackOverflow ecc. ecc.) cercando di creare un database "senza stato" sembra un esercizio piuttosto inutile.

    
risposta data 03.06.2013 - 04:15
fonte

Leggi altre domande sui tag