Vincoli di integrità in un database relazionale - dovremmo trascurarli?


10

Sono in una discussione permanente con gli sviluppatori dell'azienda in cui lavoro perché dicono che è meglio sbarazzarsi dell'applicazione della relazione (tramite le definizioni dei vincoli FOREIGN KEY) in un database relazionale al fine di accelerare le query di grandi dimensioni e ottenere meglio prestazione.

La piattaforma in esame è MySQL 5.x e non è stata impostata alcuna chiave ESTERA, mancano anche alcuni vincoli PRIMARY KEY delle relative tabelle che, almeno per me, non sono ragionevoli. Forse hanno ragione e io ho torto, ma non ho abbastanza argomenti per discutere di questa situazione.

Questo è l'approccio preferito da tre anni ormai. Sono nuovo in questa azienda (solo un mese) ma, dato che il prodotto "funziona", c'è esitazione a migliorare il database; nondimeno, la prima cosa che ho notato è il caricamento di una pagina in 1 minuto (sì, 60 secondi!).

Una delle affermazioni alla base dell'attuale situazione è che un database "denormalizzato" è più veloce di un database normalizzato, ma non credo sia vero.

La maggior parte delle query pertinenti include le operazioni JOIN, che le rendono molto, molto, molto lente con grandi quantità di dati (il database contiene milioni di righe).

Comunemente, la gestione delle operazioni "CRUD" è implementata a livello di codice del programma applicativo; ad esempio, per ELIMINARE alcuni dati DA, diciamo TableA:

  • è necessario prima verificare al volo se esiste qualche relazione tra le file di TableAe TableB,
  • nel caso in cui tale relazione venga "rilevata", il codice del programma dell'app non consentirà di ELIMINARE le righe pertinenti, ma
  • se per qualche motivo il codice del programma dell'app non riesce, l'operazione DELETE “avrà esito positivo”, indipendentemente dal fatto che vi sia una relazione relativa alle righe e alle tabelle interessate.

Domanda

Potresti aiutarmi a elaborare una risposta buona, accurata e solida per arricchire il dibattito?


Nota : forse qualcosa del genere è stato chiesto (e risposto) prima, ma non sono riuscito a trovare nulla tramite Google.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Paul White 9

Risposte:


12

Se, come indicato nel tuo post, l'intenzione è quella di creare un database relazionale (RDB per brevità) e, pertanto, si prevede che funzioni come tale, la risposta breve è:

  • No, non dovresti trascurare i vincoli di integrità dei dati .

L'obiettivo primario dovrebbe essere quello di gestire i dati pertinenti così come sono, una risorsa organizzativa piuttosto preziosa, e un modo affidabile per raggiungere detto obiettivo sta impiegando mezzi tecnici che sono supportati da una solida teoria.

Pertanto, come professionisti del database, è possibile sfruttare i meccanismi del modello relazionale all'avanguardia ed eleganti forniti dal Dr. EF Codd per far rispettare le regole aziendali ed evitare i problemi che potrebbero sorgere se non fossero utilizzati.

A questo proposito, condividerò (a) la mia opinione generale sui vincoli e anche (b) diverse considerazioni sullo stato delle cose del database e sull'ambiente di lavoro in questione come segue.

Vincoli chiave estera, relazioni di dati e integrità referenziale

Un RDB deve riflettere le caratteristiche del contesto aziendale di interesse con elevata precisione, il che richiede sicuramente un'analisi approfondita a livello concettuale condotta da un modellista o designer che segue le migliori pratiche, contando con l'assistenza indispensabile degli esperti del business. Tale analisi deve fornire la corretta identificazione e formulazione delle regole commerciali applicabili .

Di conseguenza, se tale modellatore ha identificato l'esistenza di interrelazioni tra i dati rilevanti, deve configurare le corrispondenti restrizioni a livello logico in modo che il sistema di gestione del database (DBMS) possa garantire che i dati rimangano coerenti con le caratteristiche esatte e regole determinate nell'analisi di cui sopra in ogni momento .

Per quanto riguarda il database in discussione, si può dedurre che le relative interrelazioni sono state identificate, dal momento che si menziona che c'è un tentativo procedurale (e facile da eludere) di farli rispettare al di fuori delle strutture DBMS, a causa del codice del programma applicativo (che è un approccio pre-relazionale) che in ogni caso deve "toccare" il database per provare a validare l'integrità di tali interrelazioni.

Tuttavia, come sapete, questa non è la tecnica ottimale per proteggere l' integrità referenziale , perché la scienza relazionale ha prescritto uno strumento molto potente per questo scopo, vale a dire i vincoli FOREIGN KEY (FK). Questi vincoli sono molto facili da creare (tramite l'approccio dichiarativo superiore) in quanto sono frasi singole che evitano il ricorso a procedure ad hoc non necessarie e soggette a errori. È molto utile notare che la velocità di esecuzione dei vincoli di FK è stata altamente ottimizzata da programmatori specializzati (e i principali produttori di piattaforme ci hanno lavorato già da decenni).

Inoltre, poiché un RDB deve essere un componente software indipendente (auto-protettivo, auto-descrittivo, ecc.) A cui è possibile accedere da più programmi applicativi (desktop, automatico, web, mobile, loro combinazioni), non dovrebbe essere "Accoppiato" con il codice di una di queste app.

Allo stesso modo, i dati - essendo una risorsa organizzativa significativa - tendono naturalmente a sopravvivere a programmi applicativi, programmatori di applicazioni, piattaforme di sviluppo di applicazioni e paradigmi di programmazione.

Vincoli PRIMARY KEY e implicazioni di righe duplicate

Quando —concettualmente parlando— un particolare tipo di cosa è stata considerata significativa in un ambiente aziendale, un modellatore di database deve (1) determinare le sue caratteristiche rilevanti —i, le sue proprietà —, confermare detto tipo di cosa come prototipo di istanze di entità - cioè, un tipo di entità— e (2) lo rappresentano tramite una tabella che è integrata da una o più colonne in un disegno logico.

Quindi, proprio come è fondamentale distinguere ogni singola istanza di un determinato tipo di entità nel mondo reale, anche ogni riga racchiusa in una tabella deve essere distinta in modo univoco. Se una tabella non ha alcun KEY dichiarato, alla fine manterrà i duplicati e se ci sono due o più righe che mantengono esattamente gli stessi valori, allora hanno tutti lo stesso significato , rappresentano tutti lo stesso fatto .

Su quel punto, le righe duplicate dovrebbero essere scartate per diversi motivi. Da un punto di vista teorico, il progettista deve assicurarsi che ogni riga sia sempre unica allo scopo di avere tabelle che funzionano in modo relazionale come il sotto-linguaggio dei dati SQL consente (con importanti ripercussioni sulle operazioni di manipolazione dei dati). Inoltre, dal punto di vista informativo, se più righe rappresentano lo stesso fatto, la loro registrazione non è solo superflua ma dannosa , come di seguito esemplificato:

  • Supponiamo che qualcuno abbia inserito due righe identiche in una determinata tabella.
  • Successivamente, arriva qualcun altro e aggiorna solo un'occorrenza dei duplicati. Di conseguenza, l'altra occorrenza non è più aggiornata.
  • Successivamente, un'altra persona aggiorna l'evento che non era stato modificato finora. In questo modo, entrambi i duplicati hanno subito diverse modifiche in punti distinti nel tempo.
  • Successivamente, quando qualcuno è interessato a selezionare le informazioni trasmesse dalle righe in questione, può trovarne due diverse "versioni".

In questo modo:

  • Quale "versione" può essere considerata quella corretta e affidabile?
  • Quale riflette accuratamente il mondo reale?

Come sapete, questo fenomeno può anche avere implicazioni legali, una circostanza che sicuramente ha un'importanza enorme.

Inoltre, il tempo e gli sforzi che devono essere impiegati per gestire tali contraddizioni (forse attraverso una sorta di "sincronizzazione degli aggiornamenti") dovrebbero essere meglio dedicati alle attività che producono effettivamente valore per la vostra organizzazione. Pertanto, il mantenimento di righe contraddittorie dovrebbe essere evitato dalla progettazione per mantenere intatta la coerenza di un database.

Questo è il motivo per cui l'identificazione di un PRIMARY KEY (PK) e la dichiarazione del rispettivo vincolo devono essere sempre eseguite dal progettista del database. Ma va anche detto che una tabella può avere più di una colonna o combinazione di colonne che contengono valori che identificano in modo univoco ogni riga; di conseguenza, oltre a impostare un vincolo PK (idealmente stabilito come PRIMARIO per motivi pragmatici), il progettista deve anche dichiarare uno o più TASTI ALTERNATIVI (di solito definiti tramite uno o più vincoli UNIQUE più NOT NULL) quando si applica (che è abbastanza comune).

Un'altra proprietà vantaggiosa dei PK è che, quando "migrati" su altre tabelle per prendere parte a FK singoli o compositi, possono aiutare a rafforzare i rapporti di cardinalità delle relazioni esistenti tra i dati. Tutto questo, sì, tramite impostazioni dichiarative semplici ed efficienti, assicurate dal DBMS.

Vincoli CHECK (correnti) e convalida a riga singola

Non dimentichiamoci della rilevanza dei vincoli (attuali) CHECK che, limitando in modo dichiarativo l'insieme valido di valori di colonna di una riga (che può apparire semplice, ma in realtà è una caratteristica fondamentale di un DBMS relazionale), aiuta anche a rendere certo che le regole del contesto aziendale si riflettono con precisione in ogni momento.

Dato che hai contrassegnato la tua domanda con il tag MySQL, va detto che, sfortunatamente, tale piattaforma consente la dichiarazione di tale tipo di vincolo ma, allo stesso tempo, ignora la sua applicazione! , situazione che, comprensibilmente, è stata segnalata come un bug dal 2004 .

A questo proposito, dovresti occuparti di questo fattore con altri mezzi, ad es. OPERAZIONI ACIDI , TRIGGER o altri metodi all'interno del DBMS stesso (vedi questa risposta di @ ypercubeᵀᴹ per informazioni su questo argomento) in modo che i dati continuino a essere coerenti.

Vincoli di ASSERZIONE: impostazione di ulteriori regole commerciali multi-riga e multi-tabella in modo dichiarativo

Un aspetto che, per qualsiasi motivo, è scarsamente supportato, se non del tutto, dai diversi DBMS SQL, incluso MySQL, sta abilitando vincoli multi-riga e multi-tabella in modo dichiarativo —beyond PK e FK, evidentemente—.

Da parte sua, lo standard SQL include ASSERZIONI da molti anni ormai. Non so quali regole del tuo ambiente aziendale trarrebbero beneficio da tale approccio di convalida a livello logico ma, come progettista di database, ritengo che sarebbe piuttosto utile vincolare i dati con una o più ASSERZIONI, anche se devo menzionarlo dal punto di vista degli sviluppatori DBMS, questo tipo fondamentale di strumento è stato difficile da implementare a livello fisico di astrazione.

Sembra che il fornitore e / o gli sviluppatori Oracle stiano valutando il supporto ASSERTION dal 2016 e ciò renderebbe il DBMS più conforme alle relazioni e, quindi, più robusto e competitivo. Immagino che, se (i) i loro consumatori continuano a spingere e (ii) Oracle riesce a implementare, allora (iii) altri fornitori / comunità DBMS dovranno abilitarli e il loro utilizzo inizierà a diffondersi. Certamente, sarebbe un enorme progresso nel campo della gestione del database, ed essendo uno degli strumenti più distintivi previsti dal Dr. Codd, spero personalmente che vedremo che ciò accadrà presto.

Coerenza dei dati e processo decisionale

Come discusso in precedenza, uno degli aspetti più importanti di un RDB è che garantisce di per sé la coerenza dei dati che conserva e tale coerenza viene soddisfatta solo quando l'RDB soddisfa i vincoli di integrità dichiarati dal modellatore.

A questo proposito, è obbligatorio disporre di tabelle di base (quelle stabilite in una struttura DDL) in cui l'integrità è protetta per poter creare tabelle derivate (ad es. Un'istruzione SELECT o una vista che recupera colonne da più tabelle) che siano affidabili , poiché le tabelle derivate devono essere prodotte necessariamente in termini di tabelle di base.

È noto che le persone utilizzano le informazioni come strumento principale nel processo decisionale organizzativo (e ordinario). Quindi, se le informazioni presentate da un database non sono coerenti e accurate, le decisioni basate su tali informazioni non saranno valide (per non dire altro). Ecco perché un RDB deve essere attentamente progettato e implementato: dovrebbe essere costruito per diventare una risorsa affidabile che può aiutare i suoi utenti a prendere decisioni fondate.

“Denormalizzazione”

Purtroppo, "un database" denormalizzato "è più veloce di uno normalizzato" è un malinteso ampiamente diffuso, sebbene sia anche un argomento che può essere confutato su basi logiche, fisiche e pragmatiche.

In primo luogo, la denormalizzazione implica necessariamente che una tabella di base sia stata precedentemente normalizzata (in virtù di una procedura formale , basata sulla scienza, eseguita a livello logico di astrazione di un database).

Quindi, supponendo che detta tabella sia stata effettivamente normalizzata correttamente, "denormalizzandola" (che, contrariamente al significato formale della parola, comporta l'aggiunta ad essa di colonne che appartengono e fanno anche parte di altre tabelle in un annuncio hoc moda) potrebbe favorire, ad esempio, per accelerare (a livello fisico) al trattamento di un solo o pochi particolare SELECT, mentre tale azione potrebbe, allo stesso tempo, sia minando l'esecuzione di molti altri dati associati operazioni di manipolazione (ad es. diverse istruzioni INSERT, UPDATE, DELETE e SELECT, o combinazioni delle stesse racchiuse in una singola o più OPERAZIONI ACIDI).

Inoltre, la denormalizzazione (sia formale che informale) introdurrebbe anomalie di aggiornamento / modifica che deteriorano la coerenza del database, un problema che "può" essere gestito da procedure complesse, costose e soggette a errori, quando tutto ciò può essere impedito l'inizio.

Ponteggi a livello fisico che supportano tavoli normalizzati e "denormalizzati"

Un layout logico (astratto) (design SQL-DDL) che dovrebbe essere utilizzato nel mondo reale ha chiaramente ripercussioni fisiche (concrete) che devono essere considerate.

In questo modo, una tabella "denormalizzata" sarebbe necessariamente "più ampia" (con colonne aggiuntive), il che significa che le sue righe sarebbero necessariamente più pesanti (che richiedono componenti sempre più grandi a livello fisico), quindi i processi informatici sottostanti (ad es. , quelli che hanno a che fare con il disco rigido o la memoria) possono facilmente girare più lentamente.

Al contrario, una tabella normalizzata che è ovviamente "più stretta" (con meno colonne) sarebbe un elemento "più leggero" (servito da componenti fisici sempre più piccoli) che "si comporta più velocemente", accelerando la serie di azioni relative a , ad es. scrittura e lettura dei dati.

Ciò premesso, è molto conveniente (a) normalizzare formalmente e con prudenza le relative tabelle, mantenendole come tali, e quindi (b) utilizzare qualsiasi risorsa di livello fisico in grado di ottimizzare il recupero dei dati e la velocità di modifica, ad es. una strategia di indicizzazione attenta ed efficiente, che consenta la corretta configurazione del server hardware e software, l'aggiornamento delle capacità di larghezza di banda della rete, ecc.

Il funzionamento del database in esame

I seguenti paragrafi della tua domanda hanno a che fare con la velocità delle operazioni di recupero dei dati:

[A] s il prodotto "funziona", c'è esitazione a migliorare il database; tuttavia, la prima cosa che ho notato è il caricamento di una pagina in 1 minuto (sì, 60 secondi!).

Se il caricamento di una determinata pagina richiede così tanto, è evidente che gli utenti del sistema non stanno ricevendo un buon servizio; pertanto, anche quando "funziona", il suo funzionamento non sembra affatto ottimale, punto che dimostra che le tue intenzioni di rendere più efficiente l'intero ambiente (database e app) sono ben sostenute e mostra un atteggiamento molto costruttivo.

Quindi, anche quando la scienza ti sostiene definitivamente e quindi dovresti mantenere una postura ferma, ti suggerisco di affrontare la situazione in modo diplomatico, poiché alla fine della giornata, i tuoi datori di lavoro, i tuoi colleghi e te stesso stanno unendo gli sforzi per rendere l'intera organizzazione Più di successo. Quindi, questo è un argomento che dovresti sottolineare, che, mentre stanno facendo altre cose più che bene, il miglioramento delle pratiche generali e specifiche di gestione dei dati può aiutare notevolmente a produrre una maggiore crescita organizzativa e individuale.

La maggior parte delle query pertinenti include le operazioni JOIN, che le rendono molto, molto, molto lente con grandi quantità di dati (il database contiene milioni di righe).

Vale la pena notare che l'operatore JOIN è un elemento essenziale e potente che riguarda la manipolazione relazionale dei dati. Quindi, sebbene piattaforme più robuste lo servano con esecuzioni relativamente più veloci, la circostanza che descrivi è molto probabilmente un sintomo di una progettazione non efficiente (a livello concettuale, logico e fisico di astrazione). Quindi, le mie stime a prima vista sono:

  • Le impostazioni INDEX potrebbero richiedere miglioramenti.
  • Le definizioni di tipo e dimensione delle colonne PK e FK devono essere riviste (e concordo pienamente con @Rick James riguardo alle sue considerazioni sulla PK , poiché i KEY compositi tendono ad essere molto più efficienti dei surrogati aggiunti nei casi appropriati).
  • Un'ulteriore normalizzazione (formale, basata sulla scienza) potrebbe aiutare ad alleviare questi problemi, a causa del fatto che, nelle giuste circostanze (cioè eseguite in un RDB ben progettato), i JOIN vengono eseguiti molto rapidamente .

Inoltre, sì, come cita @TommCatt nella sua risposta , a volte una riscrittura (logica) di una query modifica il suo piano di esecuzione (fisico) accelerando la lettura / scrittura dei dati, che è un fattore che dovrebbe decisamente essere preso in considerazione.


1
Bella risposta. Ricordo sempre a me stesso, considerando le prestazioni di un'implementazione, che un team di sviluppatori è molto più intelligente di quanto io abbia lavorato su questi problemi per molto tempo. I database relazionali sono al centro dei sistemi più enormi del mondo (Facebook e Twitter per citarne alcuni ovvi).
Nick Bedford,

9

La premessa di base dei tuoi sviluppatori è assolutamente sbagliata. Le chiavi esterne influiranno leggermente sulle prestazioni del DML del tuo sistema. Non vengono affatto utilizzati nelle query, pertanto non hanno alcun effetto sulle loro prestazioni. Quindi i tuoi sviluppatori non sanno di cosa stanno parlando e sono le ultime persone da cui dovresti prendere in considerazione di prendere consigli.

Le chiavi esterne svolgono un ruolo fondamentale nel mantenimento dell'integrità dei dati. Questo è molto più importante di qualsiasi piccolo miglioramento delle prestazioni ottenuto rimuovendoli (anche se fosse vero).

Non rimuovere in alcun caso FK da un database OLTP.

Inoltre, la denormalizzazione a volte accelera alcune query. Dipende, come si dice. Tuttavia, anche se c'è un certo miglioramento della velocità, in genere non vale la pena fare uno sforzo supplementare per mantenere l'integrità dei dati.

È molto raro quando la semplice messa a punto non può ottenere un miglioramento della velocità molto maggiore della denormalizzazione. È qui che un buon DBA può (finalmente) guadagnare la sua paga. Puoi anche ottimizzare le tue domande. Una volta ho preso una domanda che ha restituito una risposta in non meno di 30 minuti e l'ho fatta funzionare in meno di 8 secondi. Nessuna modifica al database, basta riscrivere la query. Certo, questo è il mio miglior record personale, quindi il tuo chilometraggio può variare, ma la denormalizzazione dovrebbe essere l'ultima cosa che provi.

Potresti anche voler evitare che le domande più complicate vengano scritte dagli sviluppatori. Chiedi loro quali dati desiderano e in quale formato li desiderano. Quindi fornisci visualizzazioni per fornirli. Le query complicate saranno le visualizzazioni. Gli sviluppatori devono solo scrivere:

select <something> from <SomeView> where <whatever>;

Suppongo anche che il tuo database sia ben progettato. Una cattiva progettazione del database, o anche di piccole parti, può davvero rallentare le cose. Ho lavorato spesso con tabelle molto grandi (miliardi di record ciascuna) con query che le univano insieme a sinistra e a destra e prevedevano (e ottenevano) risposte in frazioni di secondo. La dimensione di una tabella non è determinante per la velocità della query.

Sono davvero arrabbiato quando qualcuno dice "perché il prodotto" funziona ", c'è esitazione a migliorare il database." Se questa "esitazione" è più simile a "non sul mio orologio, amico!" allora potresti anche voler iniziare ad aggiornare il tuo curriculum. Nulla di buono viene mai da un tale ambiente e avrai la colpa di ogni fallimento futuro anche se potresti aver fatto pressioni per ore per fare un cambiamento che avrebbe impedito il fallimento. Sentirai "Ora non è un buon momento per apportare modifiche" più e più volte. Giusto. In bocca al lupo.


Una cosa da notare è che a volte sono necessarie query diverse per gli stessi dati in base alla quantità di dati da restituire. Ad esempio, una query che restituisce una singola riga (o anche solo un conteggio) potrebbe essere scritta in modo diverso rispetto a una che restituisce migliaia di record.
Joe W,

2

La modifica del titolo cambia la domanda. FOREIGN KEYssono opzionali. Loro fanno:

  • Un FK crea implicitamente un INDEXin una delle tabelle. Tale indice può essere aggiunto manualmente. (Quindi FK non è richiesto per questo.)
  • Un FK verifica l'integrità. Questa è la principale richiesta di fama dell'FK. Non è necessario un FK poiché l'applicazione può eseguire controlli simili o decidere che non è necessario un controllo. Così...
  • Il controllo di integrità costa qualcosa in termini di prestazioni; quindi rallenta l'elaborazione. (Questo di solito non è un grosso problema.)
  • Gli FK non fanno tutto ciò che tutti vogliono; questo forum è pieno di domande "why FKs do X". In particolare l' CHECKopzione non viene attivata.
  • Gli FK possono fare CASCADEcose. (Personalmente, preferisco mantenere il controllo e non dare per scontato che l'FK "farà la cosa giusta".)

Bottom line for FKs: Alcune persone insistono sugli FK; alcuni prodotti vivono perfettamente bene senza di loro. Tu decidi.

Sbarazzarsi di PRIMARY KEYInnoDB è un grosso errore. D'altra parte, sbarazzarsi di un surrogato AUTO_INCREMENTe usare un PK "naturale" composto da una (o più) colonne è spesso la cosa giusta da fare. Un caso semplice, comune, è molti: molte tabelle di mappatura, come discusso qui .

Sulla base dell'esperienza personale, suggerisco che i 2/3 dei tavoli siano meglio dell'uso di 'natural' invece di auto_inc PK.


1
Quindi ... ti affidi a un'applicazione quasi perfetta perché se uno sviluppatore fa un errore con un DELETEesempio e non hai una restrizione sul lato DB finirai per perdere i dati. Questo approccio è valido ma richiede un codice intenso e buoni test, che non avevano :)
ReynierPM

L'eliminazione eccessiva può avvenire in app o con FK. Eliminare troppo poco di solito diventa ovvio. OTOH, ho visto casi in cui eliminare troppo poco vale il costo - pensa a una "normalizzazione" in cui le cose vengono raramente eliminate. Le righe extra, inutilizzate, sono praticamente innocue.
Rick James,

Ho visto un caso "buono" senza indici su un tavolo: un tavolo di stadiazione per l'ingestione ad alta velocità. È molto transitorio (quindi InnoDB non è necessario) e deve solo essere letto completamente (quindi non sono necessari indici).
Rick James,

1
Nota un tema comune nelle mie divagazioni: non esiste una risposta singola; nessuna taglia unica.
Rick James,

Se le tue tabelle sono lunghe più di mille righe; le prestazioni non sono un problema. Se le tue tabelle sono lunghe un miliardo di righe, tutte le "regole" su normalizzazione, PK, indici, FK, UUID, ecc., Devono essere esaminate. Altrimenti il ​​db si scioglierà.
Rick James,
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.