Progettazione di database SQL per rappresentare la gerarchia di classi OO

Sono in procinto di convertire una gerarchia di classi da memorizzare in un database SQL.

Pseudo codice originale:

abstract class Note { int id; string message; }; class TimeNote : public Note { time_t time; }; class TimeRangeNote : public Note { time_t begin; time_t end; }; class EventNote : public Note { int event_id; }; // More classs deriving from Note excluded. 

Attualmente sto avendo un paio di idee su come archiviarlo in un database.

A. Archivia tutte le note in un’unica tabella ampia

La tabella conterrà tutte le informazioni necessarie a tutte le classi derivanti dalla Note .

 CREATE TABLE t_note( id INTEGER PRIMARY KEY, message TEXT, time DATETIME, begin DATETIME, end DATETIME, event_id INTEGER ); 

Le classi future derivanti dalla Note devono aggiungere nuove colonne a questa tabella.

B. Mappa ogni class in una tabella

 CREATE TABLE t_note( id INTEGER PRIMARY KEY, message TEXT ); CREATE TABLE t_timenote( note_id INTEGER PRIMARY KEY REFERENCES t_note(id), time DATETIME ); CREATE TABLE t_timerangenote( note_id INTEGER PRIMARY KEY REFERENCES t_note(id), begin DATETIME, end DATETIME ); CREATE TABLE t_eventnote( note_id INTEGER PRIMARY KEY REFERENCES t_note(id), event_id INTEGER ); 

Le classi future derivanti da Note devono creare una nuova tabella.

C. Utilizzare la normalizzazione del database e VARIANT / SQL_VARIANT

 CREATE TABLE t_note( id INTEGER PRIMARY KEY, message TEXT ); CREATE TABLE t_notedata( note_id INTEGER REFERENCES t_note(id), variable_id TEXT, -- or "variable_id INTEGER REFERENCES t_variable(id)". -- where t_variable has information of each variable. value VARIANT ); 

Le classi future derivanti dalla Note devono aggiungere un nuovo variable_id .

D. Mappare ogni class concreta in una tabella (appena aggiunta in base alle risposte correnti)

 CREATE TABLE t_timenote( id INTEGER PRIMARY KEY, message TEXT, time DATETIME ); CREATE TABLE t_timerangenote( id INTEGER PRIMARY KEY, message TEXT, begin DATETIME, end DATETIME ); CREATE TABLE t_eventnote( id INTEGER PRIMARY KEY, message TEXT, event_id INTEGER ); 

Le classi future derivanti da Note devono creare una nuova tabella.


Quale sarebbe la rappresentazione più logica in SQL essere?
Ci sono delle opzioni migliori?

In generale preferisco l’obtion “B” (cioè una tabella per la class base e una tabella per ogni sottoclass “concreta”).

Ovviamente questo ha un paio di inconvenienti: prima di tutto bisogna unire almeno 2 tabelle ogni volta che si deve leggere un’istanza completa di una sottoclass. Inoltre, la tabella “base” sarà costantemente accessibile da chiunque debba operare su qualsiasi tipo di nota.

Ma questo è generalmente accettabile se non si hanno casi estremi (miliardi di righe, tempi di risposta molto rapidi richiesti e così via).

C’è una terza opzione ansible: mappare ciascuna sottoclass in una tabella distinta. Questo aiuta a partizionare i tuoi oggetti, ma costa di più nello sforzo di sviluppo, in generale.

Vedi questo per una discussione completa.

(Per quanto riguarda la vostra soluzione “C”, usando VARIANT: non posso commentare i meriti / demeriti, perché sembra una soluzione proprietaria – cos’è Transact-SQL? E io non ho familiarità con esso).

La tua opzione “B” come descritta è praticamente un’implementazione della “Object Subclass Heirarchy” (Kung, 1990 http://portal.acm.org/citation.cfm?id=79213 )

In quanto tale, è un metodo ben consolidato e compreso. Funziona abbastanza bene. È anche estendibile attraverso più livelli di ereditarietà, nel caso tu ne abbia bisogno.

Ovviamente si perdono alcuni dei vantaggi dell’incapsulamento e dell’occultamento delle informazioni, se non si limita chi può accedere ai dati direttamente nell’interfaccia DBMS.

Puoi comunque accedervi da più sistemi, e persino da lingue, simultaneamente (ad es. Java, C ++, C #) (questo era il tema della mia tesi di Master 🙂

Hai raggiunto i 3 modi più comunemente accettati di modellare oggetti in un database relazionale. Tutti e 3 sono accettabili e ognuno ha i suoi pro e contro. Sfortunatamente, ciò significa che non esiste una risposta “giusta” tagliata e asciutta. Ho implementato ognuno di questi in momentjs diversi, e qui c’è un paio di note / avvertenze da tenere a mente:

L’opzione A ha lo svantaggio che, quando si aggiunge una nuova sottoclass, è necessario modificare una tabella esistente (ciò potrebbe essere meno appetibile all’utente rispetto all’aggiunta di una nuova tabella). Ha anche lo svantaggio che molte colonne conterranno NULL. Tuttavia, i DB moderni sembrano MOLTO meglio nella gestione dello spazio rispetto ai vecchi DB, quindi non sono mai stato troppo preoccupato per i null. Un vantaggio è che nessuna delle tue operazioni di ricerca o recupero richiederà JOIN o UNION, il che significa prestazioni potenzialmente migliori e SQL più semplice.

L’opzione B ha lo svantaggio che, se aggiungi una nuova proprietà alla tua superclass, devi aggiungere una nuova colonna alla tabella di ciascuna sottoclass. Inoltre, se si desidera effettuare una ricerca eterogenea (tutte le sottoclassi contemporaneamente), è necessario farlo utilizzando UNION o JOIN (prestazioni potenzialmente più lente e / o sql più complesse).

L’opzione C ha lo svantaggio che tutte le operazioni di recupero (anche solo per una sottoclass) coinvolgeranno un JOIN, come la maggior parte delle ricerche. Inoltre, tutti gli inserimenti coinvolgeranno più tabelle, rendendo SQL un po ‘più complesso e richiederà l’uso delle transazioni. Questa opzione sembra essere la più “pura” dal punto di vista della normalizzazione dei dati, ma raramente la utilizzo perché l’inconveniente di JOIN-per-ogni-operazione di solito rende più appetibile una delle altre opzioni.

Sarei gratificato per l’opzione A me stesso.

Dipende anche un po ‘dai tuoi scenari di utilizzo, ad esempio dovrai fare molte ricerche su tutti i tipi di note? Se sì, allora potrebbe essere meglio con l’opzione A.

Puoi sempre archiviarli come opzione A (una grande tabella) e creare Visualizzazioni per le diverse sottotampe, se lo ritieni opportuno. In questo modo, puoi ancora avere una separazione logica pur avendo una buona ricerca.

In generale, ma questo potrebbe essere vicino a una discussione religiosa, quindi, fai attenzione, credo che un database relazionale dovrebbe essere un database relazionale e non provare a imitare una struttura OO. Lascia che le tue classi facciano le cose OO, lascia che il db sia relazionale. Sono disponibili database OO specifici se si desidera estenderli al proprio archivio dati. Significa che devi attraversare il ‘disadattamento impedenza relazionale all’object’ come lo chiamano, ma di nuovo ci sono i mapper ORM per quello scopo specifico.

Vorrei andare per l’ opzione A.

La soluzione B è buona se la gerarchia delle classi è molto complessa con dozzine di classi che si ereditano a vicenda. È la soluzione più scalabile. Tuttavia, lo svantaggio è che rende l’SQL più complesso e lento.

Per casi relativamente semplici, come 4 o 5 classi che ereditano la stessa class base, ha più senso scegliere la soluzione A. L’SQL sarebbe più semplice e veloce. E il sovraccarico di avere colonne aggiuntive con valori NULL è trascurabile.

C’è una serie di modelli noti collettivamente come “Traversate di Chasms” che ho usato per molti anni. Non lasciare che i riferimenti a Smalltalk ti buttino – è applicabile a qualsiasi linguaggio orientato agli oggetti. Prova i seguenti riferimenti:

Un linguaggio di pattern per database relazionali e Smalltalk
Crossing Chasms – The Static Patterns
Crossing Chasms – The Architectural Patterns

Condividi e divertiti.

MODIFICARE

Wayback Machine si collega a tutto ciò che sono stato in grado di trovare sui pattern di Crossing Chasms: http://web.archive.org/web/20040604122702/http://www.ksccary.com/article1.htm http: // web .archive.org / web / 20040604123327 / http: //www.ksccary.com/article2.htm http://web.archive.org/web/20040604010736/http://www.ksccary.com/article5.htm http : //web.archive.org/web/20030402004741/http: //members.aol.com/kgb1001001/Chasms.htm http://web.archive.org/web/20060922233842/http://people.engr. ncsu.edu/efg/591O/s98/lectures/persistent-patterns/chasms.pdf http://web.archive.org/web/20081119235258/http://www.smalltalktraining.com/articles/crossingchasms.htm http: //web.archive.org/web/20081120000232/http://www.smalltalktraining.com/articles/staticpatterns.htm

Ho creato un documento Word che integra tutto quanto sopra in qualcosa che assomiglia a un insieme coerente, ma non ho un server su cui posso rilasciarlo per renderlo pubblicamente disponibile. Se qualcuno può suggerire un repository di documenti gratuito sarei felice di mettere il doc lì.