Devo definire le relazioni tra le tabelle nel database o solo nel codice?

60

Nella mia esperienza, molti dei progetti che ho letto in passato non avevano definizioni di relazione nel database, ma li hanno solo definiti nel codice sorgente. Quindi mi chiedo quali sono i vantaggi / svantaggi della definizione delle relazioni tra le tabelle nel database e nel codice sorgente? E la domanda più ampia riguarda altre funzionalità avanzate in database moderni come cascade, trigger, procedure ... Ci sono alcuni punti nei miei pensieri:

Nel database:

  • Correggi i dati dalla progettazione. Previene gli errori dell'applicazione che possono causare dati non validi.

  • Riduci il giro di andata e ritorno della rete all'applicazione quando inserisci / aggiorna i dati poiché l'applicazione deve fare più query per verificare l'integrità dei dati.

Nel codice sorgente:

  • Più flessibile.

  • È meglio quando si ridimensiona su più database, poiché a volte la relazione può essere cross-database.

  • Maggiore controllo sull'integrità dei dati. Il database non deve controllare ogni volta che l'applicazione modifica i dati (la complessità può essere O (n) o O (n log n) (?)). Invece, è delegato all'applicazione. E penso che la gestione dell'integrità dei dati nell'applicazione porterà a più messaggi di errore dettagliati rispetto all'utilizzo del database. Ad esempio: quando si crea un server API, se si definiscono le relazioni nel database e qualcosa va storto (come l'entità referenziata non esiste), si otterrà un'eccezione SQL con un messaggio. Il modo semplice sarà di restituire 500 al client che c'è un "Errore interno del server" e il client non avrà idea di cosa stia andando storto. Oppure il server può analizzare il messaggio per capire cosa c'è che non va, che è un modo brutto e soggetto a errori secondo me. Se lasci che l'applicazione gestisca questo, il server può generare un messaggio più significativo per il client.

C'è qualcos'altro?

Modifica: come sottolinea Kilian, il mio punto sulle prestazioni e l'amp; l'integrità dei dati è molto fuorviante. Così ho modificato per correggere il mio punto lì. Capisco perfettamente che lasciare che sia il database a gestirlo sarà un approccio più efficiente e robusto. Si prega di verificare la domanda aggiornata e dare qualche idea a riguardo.

Modifica: grazie a tutti. Le risposte che ho ricevuto sottolineano che i vincoli / relazioni dovrebbero essere definiti nel database. :). Ho ancora una domanda, dato che è alquanto fuori dalla portata di questa domanda, l'ho appena postata come una domanda separata: Gestire l'errore del database per il server API . Si prega di lasciare alcuni approfondimenti.

    
posta Yoshi 26.10.2016 - 08:47
fonte

11 risposte

70

TL; DR: i vincoli di relazione dovrebbero andare nel database.

La tua applicazione non è abbastanza grande.

Hai ragione, in effetti, che far rispettare le relazioni tra i database può richiederne l'applicazione nell'applicazione.

Vorrei sottolineare, tuttavia, che è necessario innanzitutto controllare la documentazione del software del database che si sta utilizzando e controllare le offerte di prodotti esistenti. Ad esempio, ci sono offerte di cluster su Postgres e MySQL.

E anche se alla fine hai bisogno di avere un po ' di convalida nell'applicazione, non gettare il bambino con l'acqua del bagno . Dopo tutto, meno devi fare, meglio è.

Infine, se sei preoccupato per i futuri problemi di scalabilità, temo che la tua applicazione debba subire modifiche significative prima di poter scalare comunque. Come regola generale, ogni volta che cresci 10 volte, devi riprogettare ... quindi non sprecare troppi soldi per non riuscire a prevedere i problemi di scalabilità, e invece usare i soldi per raggiungere effettivamente il punto in cui hai questi problemi.

La tua applicazione non è abbastanza corretta

Qual è la possibilità che il database che utilizzi abbia un'implementazione errata del controllo rispetto alla possibilità che la tua applicazione abbia un'implementazione errata del controllo?

E quale altera più spesso?

Scommetto che il database è corretto, in qualsiasi momento .

I tuoi sviluppatori non stanno pensando abbastanza distribuiti.

Reduce network round trip to application when insert/update data as application has to make more query(s) to check data integrity.

Bandiera rossa ! 1

Se stai pensando:

  • controlla se il record esiste
  • in caso contrario, inserisci record

allora hai fallito il problema di concorrenza più basilare: un altro processo / thread potrebbe aggiungere il record mentre procedi.

Se stai pensando:

  • controlla se il record esiste
  • in caso contrario, inserisci record
  • controlla se il record è stato inserito come duplicato

allora non è riuscito per rendere conto di MVCC: la vista del database che si ha è un'istantanea al momento dell'inizio della transazione; non mostra tutti gli aggiornamenti che si stanno verificando, e forse non ha nemmeno eseguito il commit.

Mantenere i vincoli su più sessioni è un problema davvero difficile, sii contento che sia stato risolto nel tuo database.

1 A meno che il tuo database non implementa correttamente la proprietà Serializable; ma in realtà pochi lo fanno.

Ultimo:

And I think, handle data integrity in application will let to more verbose error message than using database. Eg: when you create an API server. If you define relations in database, and something go wrong(like the referenced entity doesn't exist), you will get an SQL Exception with message.

Non analizza i messaggi di errore , se utilizzi un database di tipo produttivo dovrebbe restituire errori strutturati. Avrai qualche codice di errore, almeno, per indicare cosa c'è di sbagliato, e in base a questo codice puoi creare un messaggio di errore adatto.

Nota che la maggior parte delle volte il codice è sufficiente: se hai un codice di errore che ti dice che una chiave straniera referenziata non esiste, allora è probabile che questa tabella abbia solo una chiave esterna, quindi sai nel codice cosa il problema è.

Inoltre, siamo onesti qui, la maggior parte delle volte non gestirai gli errori con garbo comunque. Solo perché ce ne sono così tanti e non riuscirai a tenerne conto ...

... che si lega semplicemente al punto correttezza sopra. Ogni volta che visualizzi "500: Errore interno del server" perché un vincolo del database è stato attivato e non è stato gestito, significa che il database ti ha salvato, poiché hai dimenticato di gestirlo nel codice.

    
risposta data 26.10.2016 - 13:44
fonte
119

The database doesn't have to check for data integrity every time application modify data.

Questo è un punto molto fuorviante. I database sono stati creati proprio per questo scopo. Se hai bisogno di controlli sull'integrità dei dati (e se pensi di non averne bisogno, probabilmente stai sbagliando), allora lasciare che il database li gestisca è quasi certamente più efficiente e meno incline agli errori di farlo nella logica dell'applicazione.

    
risposta data 26.10.2016 - 08:53
fonte
51

I vincoli dovrebbero trovarsi all'interno del tuo database, dato che (con la migliore volontà del mondo), la tua applicazione non sarà l'unica cosa ad avere accesso a questo database.

A un certo punto potrebbe esserci bisogno di una correzione tramite script all'interno del database, oppure potrebbe essere necessario migrare i dati da una tabella a un'altra sulla distribuzione.

Inoltre potresti ottenere altri requisiti, ad es. "Il grande cliente X ha davvero bisogno di questo foglio di dati excel importato nel nostro database delle applicazioni questo pomeriggio", dove non avrai il lusso di adattare il codice dell'applicazione per adattarlo quando uno script SQL sporco lo farà in tempo.

Qui è dove l'integrità del livello del database salverà il tuo bacon.

Inoltre, immagina lo sviluppatore che prende il tuo ruolo in questa azienda dopo che te ne sei andato e viene quindi incaricato di apportare modifiche al database.

Ti odierà se non ci sono vincoli FK all'interno del database in modo che possa dire quali relazioni ha una tabella prima di cambiarla? ( Indizio, la risposta è sì )

    
risposta data 26.10.2016 - 12:46
fonte
17

Dovresti avere relazioni nel database.

Come le altre note di risposta, le prestazioni del controllo dei vincoli saranno molto meglio all'interno di quel database che all'interno dell'applicazione. I controlli sui vincoli del database sono una delle cose su cui i database sono efficaci.

Se hai bisogno di ulteriore flessibilità - ad es. i vostri noti riferimenti a database incrociati - quindi è possibile rimuovere i vincoli deliberatamente e con considerazione. Avere consistenza nel database significa che hai la possibilità di modificare quei vincoli e la certezza dell'integrità referenziale.

    
risposta data 26.10.2016 - 09:02
fonte
13
  • Non viviamo più in un back-end < - > un mondo front-end.
  • La maggior parte delle soluzioni include un front-end Web, un front-end mobile, un front-end batch e un front-end per iPad, ecc.
  • I motori di database hanno già migliaia di righe di codice testate ottimizzate per rafforzare l'integrità referenziale.

Ti puoi davvero permettere di scrivere e testare l'integrità referenziale facendo rispettare il codice quando hai il codice di risoluzione dei problemi del codice da scrivere?

    
risposta data 26.10.2016 - 15:27
fonte
2

Se non si convalida l'integrità dei dati, i vincoli, le relazioni ecc. a livello di database, significa che è molto più facile per chiunque abbia accesso al database di produzione (tramite qualsiasi altro client incluso uno strumento di accesso ai DB) per confondere i dati .

È un'ottima pratica applicare la massima integrità dei dati a livello di database. Fidati di me, questo ti farà risparmiare enormi mal di testa nel tempo in qualsiasi sistema non banale. Verrai anche più rapidamente in errore logico dell'applicazione o errori dei requisiti aziendali e incoerenze se ci penserai con attenzione.

Come nota a margine, progetta il tuo database in modo che sia il più possibile normalizzato e atomico. Nessun tavolo "Dio". Dedica moltissimo sforzo alla progettazione del tuo database per essere il più semplice possibile, idealmente con molte piccole tabelle che sono individualmente molto ben definite, con una sola responsabilità e accuratamente convalidate su tutte le colonne. Il database è l'ultimo custode della tua integrità dei dati. Rappresenta la strongzza del Castello.

    
risposta data 26.10.2016 - 16:40
fonte
2

La maggior parte delle persone dice essenzialmente "sì, in generale tu definisci sempre le relazioni nel database". Ma se le discipline dell'informatica fossero così facili, saremmo chiamati "lettori manuali di software" invece di "ingegneri del software". In realtà sono d'accordo sul fatto che i vincoli dovrebbero andare nel database, a meno che non ci sia una buona ragione per cui non dovrebbero , quindi mi permetta di fornire solo un paio di motivi che potrebbero essere considerati buoni in alcune situazioni:

Codice duplicato

A volte esiste una certa quantità di funzionalità che può essere gestita dal database nel codice dell'applicazione. Se aggiungere qualcosa come i vincoli al database sarebbe ridondante, potrebbe essere meglio non duplicare la funzionalità, perché si stanno violando i principi di DRY e si potrebbe peggiorare l'atto di manipolazione di mantenere sincronizzati il database e il codice dell'applicazione.

Sforzo

Se il tuo database sta già facendo ciò che è necessario fare senza l'utilizzo di funzionalità avanzate, potresti valutare dove devono essere collocati tempo, denaro e impegno. Se l'aggiunta di vincoli prevenisse un errore catastrofico e quindi salvasse un sacco di soldi, allora probabilmente ne vale la pena. Se si aggiungono vincoli che dovrebbero essere mantenuti, ma sono già garantiti di non essere mai violati, si sta perdendo tempo e si sta inquinando il codice base. Garantito è la parola chiave qui.

Efficienza

Normalmente non è una buona ragione, ma in alcuni casi potresti avere un certo requisito di prestazioni. Se il codice dell'applicazione può implementare una determinata funzionalità in un modo più rapido rispetto al database e sono necessarie prestazioni extra, potrebbe essere necessario implementare la funzione nel codice dell'applicazione.

Controllo

Abbastanza legato all'efficienza. A volte hai bisogno di un controllo a grana fine su come viene implementata una funzionalità e, a volte, se il database lo gestisce, lo nasconde dietro una scatola nera che devi aprire.

Punti di chiusura

  • I database sono scritti nel codice. Non c'è nulla di magico che fanno che non puoi fare nel tuo codice.
  • Niente è gratuito. Vincoli, relazioni, ecc. Usano tutti i cicli della CPU.
  • Le persone nel mondo NoSQL vanno d'accordo senza le tradizionali funzioni relazionali. Ad esempio, in MongoDB, la struttura dei documenti JSON è sufficiente per supportare un intero database.
  • L'uso cieco e ignorante delle funzionalità avanzate del database non può garantire alcun vantaggio. Potresti accidentalmente far funzionare qualcosa solo per romperlo più tardi.
  • Hai fatto una domanda molto generale senza elencare requisiti o vincoli specifici. La vera risposta alla tua domanda è "dipende".
  • Non hai specificato se si trattava di un problema su scala aziendale. Altre risposte stanno parlando di cose come i clienti e l'integrità dei dati, ma a volte queste cose non sono importanti.
  • Suppongo che tu stia parlando di un database relazionale SQL tradizionale.
  • La mia prospettiva deriva dall'aver abbandonato l'uso di tonnellate di vincoli e chiavi esterne in piccoli progetti (fino a 50 tabelle), e senza notare alcun inconveniente .

L'ultima cosa che dirò è che saprai se non dovresti inserire la funzionalità nel database. Se non sei sicuro, probabilmente stai meglio usando le funzionalità del database, perché di solito funzionano molto bene.

    
risposta data 27.10.2016 - 08:13
fonte
0

Come sempre, ci sono molte risposte. Per me ho trovato una regola semplice (beh, funziona solo per un approccio model-centric). Di solito, mi concentro solo sui diversi livelli di applicazioni.

Se il modello è costituito da più entità e ci sono dipendenze tra le entità, il livello di persistenza dovrebbe riflettere tali dipendenze con le sue possibilità. Quindi se stai usando un RDBMS, dovresti usare anche le chiavi esterne. La ragione è semplice. In questo modo i dati sono sempre strutturati in modo valido.

Qualsiasi istanza che lavori su questo livello di persistenza può farvi affidamento. Presumo che tu stia incapsulando questo strato tramite l'interfaccia (servizio). Quindi ecco il punto in cui il design finisce e inizia il mondo reale.

Esaminare i tuoi punti, in particolare riferimenti cross-database . In tal caso, sì, non ci dovrebbe essere un riferimento implementato nel RDBMS stesso, ma nel servizio. Ma prima di seguire questa strada, non sarebbe meglio considerarlo già durante la progettazione?

Significa, se lo so già, che ci sono parti che devono essere memorizzate in un DB diverso, quindi posso metterle già lì e definirlo come modello separato. Giusto?

Stai anche precisando che l'implementazione di questo codice è più flessibile . Giusto, ma non sembra che tu abbia a che fare con un disegno incompleto? Chiediti, perché hai bisogno di maggiore flessibilità?

Il problema di prestazioni, a causa dei controlli di integrità nel DB non è reale. RDBMS può controllare tali cose molto più velocemente di qualsiasi implementazione da parte tua. Perché? Bene, devi affrontare l'interruzione dei media, l'RDBMS no. E può ottimizzare tali controlli utilizzando le sue statistiche a.s.o.

Quindi vedi, tutto torna al design. Certo che puoi dire ora, ma cosa succede se un requisito sconosciuto appare, un punto di svolta? Sì, potrebbe succedere, ma tali modifiche dovrebbero essere progettate e pianificate a.s.o ..; o)

    
risposta data 26.10.2016 - 11:30
fonte
0

Hai alcune risposte molto buone ma alcuni punti in più

L'integrità dei dati è ciò che un database è progettato per fare

Effettuare la concorrenza corretta di come eliminare FK a livello di applicazione sarebbe orrendo

La competenza nell'integrità dei dati è con un DBA

A livello di programma inserisci, aggiorna, aggiornamento collettivo, inserimento bulk, eliminazione bulk ...
Thin client, thick client, client mobile ....
L'integrità dei dati non è l'esperienza di un programmatore - un sacco di codice duplicato e qualcuno lo rovinerà

Dici di essere hackerato - sei nei guai in ogni caso, ma un hacker può fare un sacco di danni attraverso un piccolo buco se non c'è protezione dell'integrità nel database

Potrebbe essere necessario manipolare i dati direttamente tramite SQL o TSQL Nessuno ricorderà tutte le regole dei dati

    
risposta data 28.10.2016 - 16:23
fonte
0

La tua domanda non ha senso: se puoi cambiare il database, è un codice, se non puoi cambiare il database, dovrai creare i tuoi vincoli altrove.

Un database che puoi modificare è tanto più codice di qualsiasi riga di ruby, javascript, c # o ada.

La domanda su dove inserire un vincolo nel proprio sistema dovrebbe ridursi a affidabilità, costi e facilità di sviluppo.

    
risposta data 28.10.2016 - 23:58
fonte
0

Ci sono un sacco di buone risposte qui. Aggiungerò che se hai un'app scritta in linguaggio Y, puoi creare un codice simile a un vincolo di database in Y. E poi qualcuno vuole accedere al tuo database usando il linguaggio Z, dovrai scrivere di nuovo lo stesso codice. Dio ti aiuti se le implementazioni non sono esattamente le stesse. O quando un utente aziendale esperto si connette al tuo database utilizzando Microsoft Access.

La mia esperienza mi dice che quando le persone non vogliono usare i vincoli del database, è perché in realtà stanno cercando di fare qualcosa nel modo sbagliato. Ad esempio, stanno cercando di caricare in massa i dati e vogliono lasciare le colonne not-null null, per un po '. Hanno intenzione di "aggiustarlo più tardi" perché la situazione che ha reso critico il vincolo non-nullo "non può accadere in questo caso". Un altro esempio potrebbe essere quando cercano di inserire due diversi tipi di dati nella stessa tabella.

Le persone più esperte faranno un passo indietro e troveranno una soluzione che non prevede il tentativo di aggirare un vincolo. La soluzione potrebbe essere semplicemente il vincolo non è più corretto perché l'attività è cambiata, naturalmente.

    
risposta data 29.10.2016 - 19:28
fonte

Leggi altre domande sui tag