Perché i vincoli vengono applicati nel database anziché nel codice?


21

Perché i vincoli vengono applicati nel database? Non sarà più flessibile inserirlo nel codice?

Sto leggendo un libro per principianti sull'implementazione di database, quindi lo sto chiedendo come principiante. Diciamo che ho progettato un database, incluso questo modello di entità:

 entity type    |   sub-types
----------------+--------------------------------------------
   Person       |   Employee, Student,       ...
   Student      |   Graduate, Undergraduate, ...
   Employee     |   Teacher,  Administrator, ...

Vincoli attuali:

  1. Una persona registrata sul sistema può essere solo uno studente o un dipendente.
  2. L'entità persona richiede l'unicità del numero sociale, che presumiamo che ogni persona possieda solo una singola unica (ovvero una chiave primaria abbastanza buona ). (vedi # 1)

Successivamente decidiamo di rimuovere il numero 1: se un giorno il college decide che anche il Teacher( Employeesottotipo) può essere Student, seguendo i corsi nel loro tempo libero, è molto più difficile cambiare il design del database che potrebbe avere migliaia, milioni, miliardi, migliaia di voci anziché cambiare semplicemente la logica del codice: solo la parte che non ha permesso a una persona di essere registrata sia come studente che come dipendente.

(È molto improbabile, ma non riesco a pensare ad altro in questo momento. Apparentemente è possibile).

Perché ci preoccupiamo delle regole di business nella progettazione del database piuttosto che nel codice?

# 1: una nota 7 anni dopo, un esempio di vita reale:
ho visto un governo in cui a causa di un errore, gli SSN emessi erano duplicati: più persone, lo stesso SSN. Chi ha progettato il DB originale ha sicuramente fatto l'errore di non applicare questo vincolo di unicità nel database. (e in seguito un bug nell'applicazione originale? più applicazioni che utilizzano il database condiviso e non concordano dove inserire, controllare e applicare il vincolo? ...).
Questo bug continuerà a vivere nel sistema e in tutto il sistema sviluppato dopo di che si basano sul database di quel sistema originale, per molti anni a venire. Leggendo le risposte qui ho imparato ad applicare tutti i vincoli, il più possibile, saggiamente (non alla cieca) nel database per rappresentare il mondo fisico reale là fuori il meglio che posso.


2
Principalmente ci preoccupiamo che vengano applicate le regole aziendali e qual è il modo migliore per farlo.
ypercubeᵀᴹ

3
In realtà stai presentando un pessimo esempio di quali vincoli sono usati, poiché la flessibilità delle tue entità e l'espandibilità del database sono per lo più definite dalla normalizzazione. Detto questo, i vincoli sono la protezione finale contro qualsiasi dato corrotto che entri nel database, anche se l'applicazione è stata intercettata, anche se viene sviluppata una nuova applicazione, anche se viene aggiunta un'API esterna, anche se qualcuno modifica direttamente il DB. I vincoli proteggono il database, inoltre la logica aziendale dovrà fare le proprie cose prima di provare ad accedere al DB.
Niels Keurentjes,

3
In realtà, come studente universitario sono considerato sia uno studente, un dipendente e un insegnante. Quindi il tuo esempio non è davvero improbabile.
Winston Ewert,

4
Non si dovrebbe mai basare la progettazione di un database sugli oggetti dell'applicazione. Dovresti progettarlo normalmente come persona, quindi avere una tabella correlata per definire i ruoli delle persone. Quindi il problema non si presenta quando hai una tabella reale per i ruoli in modo che le persone possano avere più ruoli. Se si desidera avere un solo ruolo, vincolare la tabella in modo che peopleID sia univoco. Quando si desidera modificare, rimuovere il vincolo.
HLGEM,

L'oggetto <-> La mappatura relazionale è un'arte.
Thorbjørn Ravn Andersen,

Risposte:


34

Alcuni vincoli vengono applicati al meglio nel database e altri vengono applicati al meglio nell'applicazione.

I vincoli che vengono applicati nel modo migliore nel database sono generalmente presenti perché sono fondamentali per la struttura del modello di dati, come un contrappunto di chiave esterna per garantire che un prodotto abbia un valore valido category_id.

I vincoli applicati in un'applicazione potrebbero non essere fondamentali per il modello di dati, ad esempio tutti i prodotti FooBar devono essere blu, ma in seguito qualcuno potrebbe decidere che anche i FooBar possono essere gialli. Questa è la logica dell'applicazione che non ha davvero bisogno di essere nel database, sebbene sia possibile creare una colourstabella separata e il database può richiedere che il prodotto faccia riferimento a una voce valida da quella tabella. MA la decisione che l'unico record in coloursabbia il valore blueverrebbe comunque da qualche parte al di fuori del database.

Considera cosa accadrebbe se non avessi vincoli nel database e richiedessi che fossero applicati tutti nell'applicazione. Cosa accadrebbe se avessi più di un'applicazione che doveva funzionare con i dati? Come sarebbero i tuoi dati se le diverse applicazioni decidessero di applicare i contrapposti in modo diverso?

Il tuo esempio mostra una situazione in cui avrebbe potuto essere più vantaggioso avere il vincolo nell'applicazione piuttosto che nel database, ma forse c'era un problema fondamentale con il modello di dati iniziale troppo restrittivo e poco flessibile?


Pertanto, in base a questa risposta, la regola <a persona può esistere solo nella tabella dei sottotipi di Student o solo nella tabella dei sottotipi di Employees> deve essere applicata nel codice e il database ha <Il sottotipo di Student / Employee deve essere valido persona> vincolo. Ho ragione? (Era l'esempio del libro). Grazie.
hkoosha,

2
@loolooyyyy: Sì, penso sia corretto. Se il database applica la prima regola (che una persona può essere solo uno studente o un dipendente), la situazione che hai descritto (in cui un dipendente vuole registrarsi per una classe) è impossibile perché: la persona non può essere entrambe le cose, e non lo è persino possibile creare un secondo record "persona" perché non possono condividere i numeri di previdenza sociale che presumibilmente sono emessi da una terza parte (come il governo). Naturalmente, questo modello di dati troppo restrittivo potrebbe funzionare in alcuni casi ...
FrustratedWithFormsDesigner

2
@loolooyyyy: un altro modo per utilizzare il modello di dati originale e lasciare che gli insegnanti siano studenti potrebbe essere quello di avere un'altra tabella chiamata teachers_as_studentsche è un altro sottotipo di Studentse che ha una nuova chiave esterna a cui fare riferimento Teacherse una chiave primaria generata dal sistema , invece di un social Numero di sicurezza. In questo modo, uno "studente" è in realtà un alias per un insegnante, quindi l'insegnante può ancora registrarsi per seguire una lezione. È difficile dire con certezza quanto funzionerebbe senza vedere l'intero modello di dati.
FrustratedWithFormsDesigner,

2
Ho declassato questo. Non esiste un momento in cui un vincolo viene applicato al meglio solo nell'applicazione . Il tono di questa risposta è ponderato in modo improprio.
Evan Carroll,

3
@FrustratedWithFormsDesigner certamente, è in realtà il figlio del poster per un vincolo di chiave esterna. Supponiamo di avere tre client di versioni / build diverse del punto di accesso db, cosa farai quando smetti di spedire quel prodotto in rosso? Dove hai intenzione di memorizzare l'elenco delle possibili combinazioni di colori? Suggerimento: ho un posto centralizzato per te. E se crei la tabella color_productse colorprobabilmente sarai in grado di creare ulteriori menu a discesa con maggiore facilità: la maggior parte degli IDE / caricatori di schemi, supporta i seguenti tasti.
Evan Carroll,

35

Perché:

  1. Voglio che tutti i dati nel database siano soggetti agli stessi vincoli, non solo i nuovi dati siano soggetti ai vincoli nella versione del codice in esecuzione oggi.
  2. Voglio vincoli dichiarativi, non vincoli programmatici.
  3. I dati nel database spesso sopravvivono al codice scritto per interagire con esso oggi. E quei dati - non il codice - sono la risorsa dell'organizzazione.
  4. Il mio codice diventa molto più semplice quando so che tutti i dati sono soggetti a vincoli rigorosi. Non devo più considerare casi speciali che so che il database garantisce che è impossibile.

Solo alcuni motivi che sono importanti per me.


4
Semi-correlato a (1) e (3): i bug nel codice dell'applicazione possono essere corretti, i bug nei dati sono spesso irreparabili.
mu è troppo corto il

17

I dati probabilmente sopravviveranno a lungo al codice dell'applicazione. Se la regola è fondamentale perché i dati siano utili nel tempo (come i vincoli di chiave esterna che aiutano a mantenere l'integrità dei dati), devono trovarsi nel database. Altrimenti si rischia di perdere il vincolo in una nuova applicazione che colpisce il database. Non solo le applicazioni colpiscono i database (compresi alcuni che potrebbero non rendersi conto che esiste un'importante regola di dati) ma alcuni di essi come l'importazione di dati o le applicazioni di reporting potrebbero non essere in grado di utilizzare il livello dati impostato nell'applicazione principale di immissione dei dati. Francamente, le possibilità che ci sia un bug nel vincolo sono molto più alte nel codice dell'applicazione nella mia esperienza.

Secondo il mio parere personale (basato su oltre 30 anni di dati e sull'esperienza con centinaia di database diversi utilizzati per molti scopi diversi), chiunque non inserisca le controindicazioni nel database a cui appartiene alla fine avrà dati scarsi. A volte dati errati al punto da essere inutilizzabili. Ciò è particolarmente vero quando si dispone di dati finanziari / normativi che devono soddisfare determinati criteri per il controllo.


17

La maggior parte dei vincoli di integrità referenziale implementati al di fuori del database può essere eliminata, quindi se si desidera che i dati abbiano sempre l'integrità garantita, è necessario applicare i vincoli nel database. Punto e basta.

In genere i vincoli a livello di applicazione vengono eliminati sebbene il database legga il meccanismo di coerenza, in base al quale le sessioni non possono visualizzare i dati di altre sessioni fino a quando non viene eseguito il commit.

Ad esempio, due sessioni possono provare a inserire lo stesso valore in una colonna che deve essere unica. Entrambi possono verificare allo stesso tempo che il valore non esiste già, possono sia inserire il loro valore sia possono eseguire il commit. Un vincolo univoco implementato nel database non permetterebbe che ciò accada.

A proposito, questo non è sconosciuto ai progettisti di linguaggi applicativi. Leggi la sezione 3.10 unicità nelle guide di Ruby on Rails: convalide dei record attivi e callback

Questo helper conferma che il valore dell'attributo è univoco prima che l'oggetto venga salvato. Non crea un vincolo di unicità nel database, quindi può accadere che due diverse connessioni al database creino due record con lo stesso valore per una colonna che si intende essere univoca. Per evitarlo, è necessario creare un indice univoco nel database.


16

Vantaggi dei vincoli applicati dal database:

Semplicità : dichiarare un vincolo è significativamente più semplice che dichiarare un vincolo e scrivere il codice che imporrà tale dichiarazione.

Precisione : il codice che non hai scritto non avrà mai un bug che hai creato. I fornitori di database trascorrono del tempo assicurandosi che il loro codice di vincolo sia accurato, quindi non è necessario.

Velocità : l'applicazione non può mai avere più distribuzioni del database su cui si basa. I fornitori di database trascorrono del tempo assicurandosi che il loro codice di vincolo sia efficiente, quindi non è necessario. Il database stesso ha anche un accesso più rapido ai dati di quanto un'applicazione possa mai avere, indipendentemente dall'efficienza.

Riutilizzo : è possibile iniziare con un'applicazione su una piattaforma, ma potrebbe non rimanere così. Cosa succede se è necessario accedere ai dati da un sistema operativo diverso, hardware diverso o da un'interfaccia vocale? Avendo vincoli nel database, questo codice non deve mai essere riscritto per la nuova piattaforma e non deve mai essere sottoposto a debug per la precisione o profilato per la velocità.

Completezza : le applicazioni applicano vincoli quando i dati vengono immessi nel database e richiederebbero ulteriori sforzi per verificare che i dati più vecchi siano accurati o per manipolare i dati già presenti nel database.

Longevità : la tua piattaforma di database sopravviverà probabilmente a qualsiasi applicazione specifica.


11

Perché i vincoli vengono applicati sul server? Perché non puoi costringere i cattivi a usare il tuo client.

Per chiarire, se si sta eseguendo solo l'elaborazione delle regole di business nell'applicazione client, qualcuno che utilizza un altro strumento può connettersi al server di database e fare ciò che desidera senza essere vincolato da nessuna delle regole aziendali e dai controlli di integrità. È molto difficile impedire a chiunque di utilizzare uno strumento arbitrario in qualsiasi punto della rete.

Se si esegue il controllo di integrità sul server di database, ogni tentativo di accedere ai dati, indipendentemente dallo strumento, sarà vincolato dalle regole.


10

Alcune grandi risposte qui e a rischio di ripetere altri pensieri:

  • SSN non è necessariamente unico. Diamine, SSN non è nemmeno sempre noto, e in alcuni casi non esiste (ancora). Gli SSN possono essere riutilizzati e non tutti i dipendenti o gli studenti possono mai avere un SSN. Ciò è periferico alla domanda, ma dimostra che, indipendentemente da dove si applicano i propri vincoli, è necessario comprendere il modello di dati e il dominio abbastanza a fondo per prendere decisioni sulle regole aziendali.
  • Personalmente preferisco che i vincoli siano il più vicino possibile ai dati. Il motivo molto semplice è che non tutti useranno il codice dell'applicazione per modificare i dati nel database. Se imponi le tue regole di business a livello di applicazione e vado a eseguire una UPDATEdichiarazione direttamente sul database, come fa la tua applicazione a impedire una modifica non valida? Un altro problema con le regole aziendali nell'app è che la ricompilazione / ridistribuzione può essere difficile, specialmente per le app distribuite in cui è possibile che non tutti ottengano l'aggiornamento contemporaneamente. Infine, la modifica delle regole di business nell'applicazione non fa assolutamente nulla sui dati già esistenti che violano le nuove regole: se aggiungi il nuovo vincolo ai dati, devi correggerli.
  • Potresti essere in grado di giustificare controlli multipli e ridondanti a vari livelli. Tutto dipende dalla flessibilità delle metodologie di distribuzione, dalla probabilità che si verifichi una modifica e da quanto sia difficile sincronizzare una modifica delle regole di business nel database e in altri livelli. Un argomento convincente per ripetere i controlli a livello di app è che puoi potenzialmente impedire un round trip al database solo per fallire un vincolo lì (a seconda della natura del vincolo e se si basa su dati esistenti). Ma se dovessi scegliere l'uno o l'altro, lo metterei nel database per i motivi sopra.

Nel caso in cui menzioni esplicitamente, dove improvvisamente permetti qualcosa che non era precedentemente consentito, questo non è davvero un problema: rimuovi qualsiasi vincolo lo imponga, indipendentemente da dove esiste. Nel caso opposto, dove all'improvviso agli insegnanti non è più permesso di essere studenti, potenzialmente hai un sacco di dati da ripulire, sempre a prescindere da dove esistesse il vincolo in precedenza.


9
  1. Il database può controllare efficacemente i vincoli. Meglio del codice.

  2. I vincoli di integrità aiutano il database a trovare un piano di esecuzione efficace

  3. L'applicazione vede una lettura coerente, quindi difficilmente può garantire unicità. Mentre il database può anche vedere dati non sottoposti a commit.


8

Risposta breve ... per preservare l'integrità dei dati (es. Precisione e validità).

Un'eccezione ...
Se il database memorizza solo i dati di una singola applicazione per un singolo utente, come nella maggior parte dei database Sqlite, potrebbe non essere necessario vincoli. In realtà, di solito non lo fanno, in modo da mantenere il tempo di accesso così veloce che non è misurabile.

Per tutto il resto ... I
database servono sempre due master che chiamerò editor e utenti .

I redattori inseriscono principalmente i dati nel database e recuperano i dati uno o un piccolo numero di record alla volta. Le loro preoccupazioni principali sono l'accesso rapido e accurato a tutti i relativi dati e l'archiviazione rapida e affidabile delle loro modifiche.

Gli utenti recuperano principalmente dati e si preoccupano soprattutto di accedere rapidamente a informazioni indiscutibilmente accurate. Spesso hanno bisogno di vari conteggi, aggregazioni ed elenchi che in passato venivano generati in quelle iconiche pile di stampe di carta verde spesse un piede ma di solito finiscono oggi sulle pagine web.

I progetti di sviluppo del database sono quasi sempre avviati per volere degli utenti , ma la progettazione viene guidata dalle esigenze di inserimento dei dati e registrazione alla volta degli editori . Pertanto, gli sviluppatori inesperti spesso rispondono all'esigenza immediata di velocità (principalmente, di sviluppo ) non ponendo vincoli nel database.

Se una sola applicazione verrà mai utilizzata per apportare modifiche ai dati per l' intera vita del database e tale applicazione viene sviluppata da uno o un numero limitato di individui ben coordinati, allora potrebbe essere ragionevole fare affidamento su l'applicazione per assicurare l'integrità dei dati.

Tuttavia, per quanto fingiamo di poter prevedere il futuro, non possiamo.

Lo sforzo di produrre qualsiasi database è troppo prezioso per poterlo buttare via. Come una casa, il database verrà ampliato, modificato e rinnovato molte volte. Anche quando viene completamente sostituito, tutti i dati verranno migrati nel nuovo database preservando tutte le vecchie regole e relazioni aziendali.

I vincoli implementano tali regole e relazioni in una forma concisa e dichiarativa nel motore di database stesso dove sono facilmente accessibili. Senza di essi, gli sviluppatori successivi dovrebbero scorrere i programmi applicativi per decodificare tali regole. In bocca al lupo!

Questo, tra l'altro, è esattamente ciò che i programmatori COBOL del mainframe devono fare poiché quei enormi database sono stati spesso creati prima che avessimo motori e vincoli relazionali. Anche se migrati su un sistema moderno come DB2 di IBM, a volte i vincoli non sono completamente implementati poiché la logica delle vecchie regole, forse incorporate in una serie di programmi "batch" COBOL, può essere così contorta da non essere pratica da convertire. Gli strumenti automatizzati possono invece essere utilizzati per convertire la vecchia COBOL in una versione più recente con interfacce per il nuovo motore relazionale e con un po 'di modifiche, l'integrità dei dati viene preservata ... fino a quando non viene scritta una nuova app che corrompe delicatamente tutto e l'azienda viene trascinata in tribunale per, diciamo, escludendo migliaia di proprietari di case che non avrebbero dovuto avere.


7

Oltre agli altri commenti ...

Se / quando si dispone di un database in cui una determinata tabella può essere aggiornata da una o più applicazioni o percorsi di codice, posizionare i vincoli appropriati nel database significa che le applicazioni non duplicheranno lo "stesso" codice di vincolo. Ciò è vantaggioso semplificando la manutenzione (riducendo il numero di posizioni da modificare se / quando si verifica una modifica del modello di dati) e si assicura che i vincoli vengano applicati in modo coerente indipendentemente dall'applicazione che aggiorna i dati.


5

Personalmente, penso che sia più facile creare e modificare i vincoli che creare trigger, ad esempio, che sarebbe un modo per far rispettare le regole aziendali utilizzando il codice sorgente.

Inoltre, i trigger hanno meno probabilità di essere portatili, poiché di solito sono scritti in linguaggi specifici del fornitore, come PL / SQL.

Ma se i vincoli non soddisfano le tue esigenze, puoi sempre utilizzare i trigger per applicare le regole aziendali.


5
Inoltre, i trigger non garantiscono l'integrità, a causa di problemi di coerenza nella lettura.
David Aldridge,

3

Essi devono sempre essere applicate nel database prima perché,

  1. Il database garantisce l'integrità tra i diversi client. È possibile avere client diversi su piattaforme diverse accedere al database. I vincoli nel database non rischiano problemi di integrità quando si crea un nuovo client. Ciò consente di evitare di dover rispondere ai propri vincoli in caso di riscrittura o di un punto di accesso aggiuntivo.
  2. Il database ha un DSL per la creazione di vincoli: DDL SQL!
  3. Il database fornisce l'accesso a tali vincoli nei cataloghi di sistema in modo che un ORM o un "caricatore di schemi" corretto possa leggere tali vincoli e introdurli nell'applicazione. Ad esempio, se il database specifica che si dispone di un varchar(5)tipo, è probabile che sia possibile trovare uno schema che carica ORM per la propria lingua specifica che associa il tipo di lingua al tipo di schema e assembla il proprio vincolo sulla dimensione.DBIx for Perl is one such schema loader; eccone un altro per Entity Framework . Le capacità di questi caricatori variano, ma tutto ciò che possono fornire è un buon inizio per garantire l'integrità nell'app senza il viaggio nel database.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.