PDA

Visualizza la versione completa : [POSTGRESQL] Progettare rispettando la normalizzazione


Shadow976
25-08-2009, 09:47
Come diceva un utente ieri sera, la notte ha portato consiglio!

E' noto che i criteri di normalizzazione dei database servono per assicurarne l'integrità di dati, evitarne ridondanze e mantenere prestazioni elevate. Di conseguenza un sistema ben progettato non dovrebbe prescindere da esse, ed anzi rispettarle quanto più possibile. Personalmente, sto cercando di "spingermi" sino alla terza forma normale e sono impattato in una apparente contraddizione in merito alla quale sono a chiedervi lumi.

1. In una tabella vanno evitate ridondanze; se un campo potrebbe evitarsi in quanto le sue veci sono già svolte da uno o più campi tra i rimanenti, non ci sono buone ragioni per mantenere quel campo superfluo che appesantisce inutilmente la struttura della tabella.

2. E' buona norma tenere in ogni tabella una chiave id autoincrementale da candidare a chiave primaria, in modo da sfruttare il suo tipo numerico per rendere più veloci le ricerche ed in generale le operazioni.

Bene, quando una tabella possiede una coppia di valori integer che già di per sé presi in coppia saranno sempre univoci, vale la pena aggiungere un ulteriore campo, appunto un id autoincrementale, che diventerà la chiave primaria della tabella? Io direi di sì, anche a 'logica' si capisce subito, in questo modo, che si migliorano le prestazioni. Però, in questo modo, si aggiunge un campo che in fondo sarebbe superfluo rispetto agli altri, violando in apparenza le regole sulla normalizzazione. Quindi... Meglio aggiungerlo o no? Possibile che aggiungendo quell'id tali norme siano violate? A me pare stranissimo. Un conto è sconsigliare l'aggiunta di un campo quando la sua funzione è puramente informativa (ad esempio aggiungere il campo "nomeprovincia" quando ho già il campo "siglaprovincia"), un conto è aggiungere un campo per fargli svolgere una funzione ben precisa, come quella di una chiave primaria. Che ne dite? Sicuri che aggiungendo quell'id io debba violare tali regole?

standard
25-08-2009, 10:06
Originariamente inviato da Shadow976
Bene, quando una tabella possiede una coppia di valori integer che già di per sé presi in coppia saranno sempre univoci, vale la pena aggiungere un ulteriore campo, appunto un id autoincrementale, che diventerà la chiave primaria della tabella? Io direi di sì
Anch'io direi di sì. Anche perchè c'è differenza tra la primary key (chiave tecnica) di una tabella e un unique constraint (vincolo di univocità) della tabella.
La prima è tecnica.
La seconda è logica (o funzionale).

Io comunque sono per la reale comprensione degli aspetti teorici, che si ottiene semplicemente domandosi il perchè e verificandone i benefici sul campo (daltronde queste norme/teorie sono il frutto di anni di esperienza su progetti reali).

Quindi se tu usassi la sola chiave logica potresti trovarti nella condizione di avere una chiave primaria composta da più campi, situazione scomoda per il fatto che eventuali legami o vincoli di foreign key dovrebbero portarsi in giro insiemi di campi (oltre al fatto che sparpagli informazioni funzionali nel tuo DB ogni volta che hai bisogno di un legame).

comas17
25-08-2009, 10:13
Ecco, quoto anche io (anche perchè lo avevo suggerito io ieri sera.... :stordita: )

Come dice giustamente standard, la mancanza di una chiave primaria "autoincrementale" ti obbligherebbe ad utilizzare (in giro per il database) della combinazione dei campi che fanno "logicamente" chiave e questo può rivelarsi estremamente complesso e scomodo

In questo caso stiamo parlando di 2 integer ma in linea teorica potresti ritrovarti che la tua chiave "logica" sia fatta da varchar(20) + datetime....

Non solo è più scomoda da gestire ma occupa infinitamente più spazio, obbligandoti a replicare in tutte le tabelle collegate le colonne varchar(20) + datetime

Tanto per tornare all'esempio persone_versioni, se tu utilizzi un campo autoincrementale anche nella tabella persone_versioni (anche se è formalmente ridondante) ti ritrovi poi che nella tabella "eventi" in cui vuoi registrare i dati delle persone_versioni, puoi utilizzare il solo campo autoincrementante invece della coppia "id socio" e "versione" (non è correttissima dal punto di vista puramente formale ma ti fa risparmiare spazio...)

Shadow976
25-08-2009, 10:14
Quesito concluso, grazie tantissimo. E grazie anche all'utente così gentile che risolvendo il problema sulla storicizzazione mi ha fatto riflettere in tal senso.

Shadow976
25-08-2009, 10:14
Comas ho letto solo ora la tua gentile risposta, vorrei ringraziare anche te.

standard
25-08-2009, 10:17
Originariamente inviato da Shadow976
2. E' buona norma tenere in ogni tabella una chiave id autoincrementale da candidare a chiave primaria, in modo da sfruttare il suo tipo numerico per rendere più veloci le ricerche ed in generale le operazioni.

Sul tema "Auto-incrementale" non sono molto d'accordo. Forse sono gusti, ma valuta questo:
1. l'ID auto-incrementale è una funzionalità specifica del DB che usi (non tutti i DB hanno questa caratteristica, ad es. Oracle)
2. "deleghi" alcune logiche tecniche (l'incremento del tuo ID) al DB, perdendo un po' di controllo (ammetto che questo è più un aspetto legato al mio gusto, ma fino ad un certo punto).
3. potrebbe comunque non risparmiarti lavoro. Spesso infatti occorre verificare che dati uguali non siano già presenti sulla tua base dati. Puoi certamente sfruttare vincoli di univocità per impedirlo, ma spesso e volentieri si è costretti a rileggere i dati per capire se fare una insert o un update dell'entità imputata nel data-entry

comas17
25-08-2009, 10:27
Originariamente inviato da standard
Sul tema "Auto-incrementale" non sono molto d'accordo. Forse sono gusti, ma valuta questo:
1. l'ID auto-incrementale è una funzionalità specifica del DB che usi (non tutti i DB hanno questa caratteristica, ad es. Oracle)


Corretto, esiste ovviamente il modo per gestirlo anche in Oracle, ma in effetti la funzionalità "nativa" in Oracle non c'è
http://www.oracle-base.com/articles/misc/AutoNumber.php


Originariamente inviato da standard
2. "deleghi" alcune logiche tecniche (l'incremento del tuo ID) al DB, perdendo un po' di controllo (ammetto che questo è più un aspetto legato al mio gusto, ma fino ad un certo punto).


Anche questo e' vero ma ti risparmi però di dover ogni volta "ricalcolare" (e può non essere banale nei casi di accesso multiplo più o meno contemporaneo) quale sia il/i nuovo/i ID da utilizzare

Shadow976
25-08-2009, 10:29
?

E come creeresti allora quel campo integer da candidare a chiave primaria? Suppongo comunque con un sistema che si incrementi di 1 ad ogni inserimeto, ma lasciando l'incomodo dell'incremento all'applicazione e non al database? Ho capito bene?

standard
25-08-2009, 10:39
Originariamente inviato da Shadow976
?

E come creeresti allora quel campo integer da candidare a chiave primaria? Suppongo comunque con un sistema che si incrementi di 1 ad ogni inserimeto, ma lasciando l'incomodo dell'incremento all'applicazione e non al database? Ho capito bene?
Quello che farei per disaccoppiare l'applicativo dal DB specifico è:
1. sul DB: lasciare comunque le primary key come numerici (ma non auto-incrementali)
2. sul DB: utilizzare o simulare l'uso di oggetti "sequence". Nel caso di DB che non lo prevedano, è sufficiente definire una tabella e un paio di stored function che facciano il lavoro di incrementare e restituirti i valori dei tuoi contatori. Soluzione legata ovviamente al DB che usi, ma il tuo applicativo non se ne accorge.
3. lato applicativo: gestire le funzionalità leggendo e/o aggiornando queste sequences in fase di inserimento.

Shadow976
25-08-2009, 10:51
Meno male, è esattamente quello che avevo fatto! Quando parlavo di autoincremento davo per scontato che in Postgre avevo

1) Creato una sequenza (per maggior ordine e rigore progettuale, una diversa sequenza per ogni tabella, per non associare una sequenza a più tabelle);
2) Creato id integer;
3) Associato il valore di default di tale campo alla suddetta sequenza.

Grazie anche per questa tua ultimissima dritta!

Loading