Il mio progetto attuale è essenzialmente una corsa al sistema di gestione dei documenti del mulino.
Detto questo, ci sono alcune rughe (sorpresa, sorpresa). Mentre alcune delle rughe sono abbastanza specifiche per il progetto, credo che siano emerse alcune osservazioni e domande generali che non hanno una risposta canonica (che potrei trovare, comunque) e che sono applicabili a un dominio problematico più ampio . C'è molto qui e non sono sicuro che sia adatto al formato di domande e risposte StackExchange, ma penso che a) una domanda responsabile eb) abbastanza non specifico da poter essere di beneficio alla comunità. Alcune delle mie considerazioni sono specifiche per me, ma penso che la domanda potrebbe essere utile a chiunque debba affrontare la decisione su SQL vs NoSQL vs entrambi.
Lo sfondo:
L'app Web che stiamo creando contiene dati di natura chiaramente relazionale, nonché dati orientati ai documenti. Vorremmo avere la nostra torta e mangiarla anche noi.
TL; DR: Penso che il n. 5 sotto superi il test dell'olfatto. Fai? Qualcuno ha esperienza con una tale integrazione di SQL e NOSQL in una singola applicazione? Ho cercato di elencare tutti i possibili approcci a questa classe di problemi nel seguito. Ho perso un'alternativa promettente?
complessità:
- Esistono molte diverse classi di documenti. I requisiti richiedono già dozzine di documenti diversi. Questo numero aumenterà sempre e solo. Il caso migliore sarebbe quello in cui potremmo sfruttare un semplice linguaggio specifico di dominio, generazione di codice e uno schema flessibile in modo che gli esperti di dominio possano gestire l'aggiunta di nuove classi di documenti senza l'intervento di DBA o programmatori. (Nota: già consapevole che stiamo vivendo la Decima Regola di Greenspun )
- L'integrità delle precedenti scritture riuscite è un requisito centrale del progetto. I dati saranno fondamentali per l'azienda. La semantica ACID completa sulle scritture può essere sacrificata a condizione che le cose che vengono scritte con successo rimangano scritte.
- I documenti sono essi stessi complessi. Il documento prototipo nel nostro caso specifico richiederà l'archiviazione di oltre 150 parti distinte di dati per istanza del documento. Il caso patologico potrebbe essere un ordine di grandezza peggiore, ma certamente non due.
- Una singola classe di documenti è un obiettivo mobile soggetto ad aggiornamenti in un secondo momento.
- Ci piace il materiale gratuito che riceviamo da Django quando lo colleghiamo a un database relazionale. Vorremmo mantenere i freebies senza dover saltare indietro di due versioni di Django per usare la forcella django-nonrel. Scaricare l'ORM interamente è preferibile al downgrade a 1.3.
In sostanza, si tratta di un miscuglio di dati relazionali (le tue cose tipiche delle app web come utenti, gruppi, ecc., Così come i metadati dei documenti che dovremo essere in grado di tagliare e tagliare con query complesse in tempo reale) e dati dei documenti (ad es. le centinaia di campi per i quali non abbiamo interesse a unirci o interrogare - il nostro unico caso d'uso per i dati sarà quello di mostrare il singolo documento in cui sono stati inseriti).
Volevo fare un controllo di integrità (se controlli la mia cronologia dei post, sono piuttosto esplicito sul fatto che non sono un DBA) sul mio metodo preferito, nonché elencare tutte le opzioni che ho trovato per gli altri a risolvere problemi sostanzialmente simili che coinvolgono dati sia relazionali che non relazionali.
Soluzioni proposte:
1. Una tabella per classe di documenti
Ogni classe di documenti ottiene la propria tabella, con colonne per tutti i metadati e dati.
vantaggi:
- È in gioco il modello di dati SQL standard.
- I dati relazionali vengono gestiti nel miglior modo possibile. Denormalizzeremo più tardi se necessario.
- L'interfaccia di amministrazione integrata di Django è a suo agio nell'introspezione di queste tabelle e l'ORM può vivere felicemente con il 100% dei dati pronti all'uso.
svantaggi:
- Incubo di manutenzione. Dozzine (centinaia?) Di tabelle con (decine di?) Migliaia di colonne.
- Logica a livello di applicazione responsabile di decidere esattamente su quale tabella scrivere. Rendere il nome della tabella un parametro per una query puzza.
- Fondamentalmente tutte le modifiche alla logica aziendale richiedono modifiche allo schema.
- I casi patologici potrebbero richiedere lo striping dei dati per singoli moduli su più tabelle (vedi: Qual è il numero massimo di colonne in una tabella PostgreSQL? ).
- Probabilmente avremmo bisogno di trovare un vero DBA onesto a Dio che senza dubbio finisca per odiare la vita e noi.
2. Modellazione EAV
C'è solo una tabella dei campi. La modellazione di entità-attributo-valore è già ben compresa. L'ho incluso per completezza. Non credo che nessun nuovo progetto avviato nel 2013 sarebbe apposta con un approccio EAV.
vantaggi:
- Facile da modellare.
svantaggi:
- Più difficile da interrogare.
- Il livello DB non ha più una rappresentazione diretta di ciò che costituisce un oggetto a livello di app.
- Perderemmo il controllo dei vincoli a livello di DB.
- Il numero di righe su una tabella aumenterà 100s-1000s di volte più velocemente. Probabile punto di dolore futuro, dal punto di vista delle prestazioni.
- Indicizzazione limitata possibile.
- Lo schema DB non ha senso per quanto riguarda ORM. Le batterie incluse nel materiale delle app Web vengono conservate ma i modelli di dati personalizzati richiedono query personalizzate.
3. Utilizzare i campi hstore o json di PostgreSQL
Ognuno di questi tipi di campi farebbe il trucco per la memorizzazione di dati schematici nel contesto di un DB relazionale. L'unica ragione per cui non salto a questa soluzione è immediatamente è relativamente nuovo (introdotto nella versione 8.4, quindi non che nuovo), Io ho zero precedente esposizione ad esso e io sono sospettoso. Mi sembra sbagliato per gli stessi motivi per cui mi sentirei a disagio nel lanciare tutti i miei dati belli e facilmente normalizzati in Mongo, anche se Mongo è in grado di gestire i riferimenti tra i documenti.
vantaggi:
- Otteniamo i vantaggi di Django ORM e della gestione integrata delle sessioni e delle autorizzazioni.
- Tutto rimane in un backend che abbiamo già utilizzato con successo su altri progetti.
svantaggi:
- Nessuna esperienza con questo, personalmente.
- Non sembra una funzionalità molto utilizzata. Sembra che vengano raccomandati un po 'alle persone che guardano alle soluzioni NOSQL, ma non vedo molte prove che vengano scelte. Questo mi fa pensare che mi manchi qualcosa.
- Tutti i valori memorizzati sono stringhe. Perdita del controllo dei vincoli a livello di DB.
- I dati nell'hstore non verranno mai mostrati all'utente a meno che non visualizzino specificamente un documento, ma saranno i metadati memorizzati in più colonne standard. Stiamo battendo quei metadati e temo che gli hstore piuttosto grandi che creeremo potrebbero avere degli svantaggi nelle prestazioni.
4. Orientamento completo al documento
Rendi tutti i documenti (in senso MongoDB). Crea una singola raccolta di tipi Document
e chiamala un giorno. Porta anche in mongo tutti i dati periferici (inclusi i dati sugli account utente, i gruppi, ecc.). Questa soluzione è ovviamente migliore della modellazione EAV, ma mi sembra sbagliato per lo stesso motivo per cui # 3 si sentiva sbagliato: entrambi hanno voglia di usare anche il martello come cacciavite.
vantaggi:
- Non è necessario modellare i dati in anticipo. Prendi una raccolta con documenti di tipo
Document
e chiamala un giorno. - Conosciute buone caratteristiche di ridimensionamento, se la raccolta dovesse crescere per comprendere milioni o addirittura miliardi di documenti.
- Il formato JSON (BSON) è intuitivo per gli sviluppatori.
- A quanto ho capito (che è solo vagamente a questo punto), essendo paranoico per quanto riguarda il livello di preoccupazione di scrittura, anche una singola istanza può fornire una sicurezza dei dati piuttosto forte in caso di qualsiasi cosa fino a un crash del disco rigido.
svantaggi:
- L'ORM è fuori dalla finestra per il baule Django. Freebies che escono dalla finestra con esso: il framework auth, il framework delle sessioni, l'interfaccia di amministrazione, sicuramente molte altre cose.
- È necessario utilizzare le funzionalità di riferimento di mongo (che richiedono più query) o denormalizzare i dati. Non solo perdiamo omaggi che abbiamo ottenuto da Django, ma perdiamo anche omaggi come JOIN che abbiamo dato per scontato in PostgreSQL.
- Sicurezza dei dati. Quando si legge su MongoDB, sembra che ci sia sempre almeno una persona che si riferisce a come salverà e perderà i tuoi dati. Non citano mai un evento particolare e potrebbe essere solo un colpo di frusta o semplicemente legato al vecchio fuoco predefinito e dimenticare la preoccupazione per la scrittura, ma mi preoccupa ancora. Ovviamente utilizzeremo una strategia di backup abbastanza paranoica (se i dati vengono danneggiati in modo silenzioso, ovviamente potrebbe non essere rilevante ...).
5. PostgreSQL e MongoDB
I dati relazionali vanno nel database relazionale e i dati del documento vanno nel database orientato al documento. La documents
tabella nel database relazionale contiene tutti i dati di cui potremmo aver bisogno per indicizzare, suddividere e tagliare, nonché un ObjectId MongoDB che utilizzeremmo quando avessimo bisogno di cercare i valori effettivi dei campi nei documenti. Non saremmo in grado di utilizzare l'ORM o l'amministratore integrato per i valori dei documenti stessi, ma non è una grande perdita poiché l'intera app è sostanzialmente un'interfaccia di amministrazione per i documenti e probabilmente avremmo dovuto personalizzare quella parte specifica dell'ORM a un livello inaccettabile per farlo funzionare nel modo che ci serve.
vantaggi:
- Ogni backend fa solo ciò in cui è bravo.
- I riferimenti tra i modelli vengono conservati senza richiedere più query.
- Manteniamo le batterie che Django ci ha fornito per quanto riguarda utenti, sessioni, ecc.
- È necessaria solo una
documents
tabella, indipendentemente dal numero di diverse classi di documenti creati. - I dati del documento meno frequentemente interrogati sono fortemente separati dai metadati molto più spesso interrogati.
svantaggi:
- Il recupero dei dati del documento richiederà 2 query sequenziali, prima sul DB SQL e poi sul MongoDB (anche se non è peggio che se gli stessi dati fossero stati archiviati in Mongo e non denormalizzati)
- La scrittura non sarà più atomica. Una scrittura contro un singolo documento Mongo è garantita come atomica e PG ovviamente può garantire l'atomicità, ma garantire l'atomicità della scrittura su entrambi richiederà logica applicativa, senza dubbio con una penalità di prestazioni e complessità.
- Due backend = due lingue di query = due programmi diversi con requisiti di amministrazione diversi = due database in lizza per la memoria.
JSON
tipo di dati. Non aver paura di usare nuove funzionalità in Postgres: il team di Postgres non rilascia funzionalità che non sono stabili. E 9.2 non è così nuovo in realtà). Inoltre, puoi utilizzare le nuove funzionalità JSON in 9.3 una volta che è lì. Se si elaborano sempre completamente i documenti nel codice dell'applicazione (anziché utilizzare SQL), è possibile anche archiviare JSON in unatext
colonna normale .