Normalizzazione: è considerato conforme suddividere valori numerici statici come un anno nella propria tabella?


16

Sto avendo un'interessante discussione con un altro progettista di database sulla normalizzazione. In questo esempio, abbiamo una tabella GameTitles e ogni record deve contenere l'anno in cui il gioco è stato rilasciato. Dice che 2NF impone che tutto debba essere normalizzato, quindi, per essere conforme, il campo dell'anno dovrebbe essere suddiviso in una tabella ReleaseYears con la sua chiave primaria a cui fa riferimento la tabella GameTitles. Dico che dovrebbe rimanere un campo sul tavolo GameTitles stesso.

La mia tesi per questo è che un anno è solo un valore numerico non primitivo che è statico per sua natura (cioè, il 2011 sarà sempre il 2011). Per questo motivo, funge da identificatore proprio e non ha bisogno di nulla per fare riferimento poiché è quello che è. Ciò introduce anche una manutenzione aggiuntiva poiché ora è necessario aggiungere un nuovo anno alla tabella solo per fare riferimento. Se prepopoli la tabella con un ampio intervallo di anni, hai record aggiuntivi che potenzialmente non avranno alcun riferimento a loro. Ciò aumenta anche le dimensioni del database poiché ora si dispone di una tabella aggiuntiva, un overhead dei record e la chiave primaria aggiuntiva per l'anno stesso. Se si tiene l'anno come campo nella tabella GameTitles, si eliminano tutti questi costi di manutenzione e costi aggiuntivi.

Pensi su questo?

modifica: voleva pubblicare questo su StackOverflow. Qualcuno può votare per eliminare questo o segnalarlo per l'attenzione?


6
Perchè così? sembra una buona misura qui.
Leigh Riffel,

La domanda che vorrei porre è: ti stai ponendo questo riguardo alla normalizzazione o alle reali esigenze di produzione? Per la produzione vorrei chiedere se è una cosa valida da fare?
jcolebrand

Risposte:


14

L'altro progettista di database ha semplicemente torto, ma anche il tuo ragionamento è sbagliato. Supponiamo di iniziare con questa tabella, che ha una singola chiave candidata, "game_title".

Table: game_titles

game_title                      year_first_released
--
The first game                  1998
The second game                 1999
Best game: the third one        2001
The fourth game                 2003
Forty-two, the end of games     2011

Valuta se è in 2NF ponendoti queste domande.

D: Prima di tutto, è in 1NF?

A: Sì, lo è.

D: Quali sono gli attributi primi (attributi che fanno parte di una chiave candidata)?

A: "game_title" è l'unico attributo primo.

D: Quali sono gli attributi non primi?

A: "year_first_released" è l'unico.

D: "year_first_released" dipende funzionalmente dall'intero "game_title" o da una sua parte?

A: L'unica chiave candidata, "game_title", è una singola colonna; non ha nemmeno parti. Quindi "year_first_released" dipende funzionalmente dall'intero "game_title".

Ecco. Hai trovato 2NF.

È possibile tagliare alcuni dei termini formali chiedendo prima se è in 1NF e quindi rispondendo a questa domanda.

D: Esistono chiavi candidate composte?

A: No.

Ecco. Hai trovato di nuovo 2NF.

Per definizione, affinché una tabella violi 2NF, deve avere almeno una chiave candidata con più di una colonna.

Ecco i motivi per cui hai rifiutato l'opinione del tuo amico.

  • Un anno è solo un valore numerico non primitivo.
  • Un anno è statico per sua stessa natura.
  • Un anno serve come proprio identificatore.
  • Una tabella di anni introduce ulteriore manutenzione.
  • Una tabella di anni potrebbe contenere righe extra a cui non si fa riferimento.
  • Una tabella di anni aumenta le dimensioni del database.

Nessuna di queste ragioni ha niente a che fare con se una tabella è in 2NF.

Nella progettazione di un database, non è sbagliato considerare problemi di manutenzione, dimensioni del database, righe senza riferimento, vincoli di intervallo e così via. È solo sbagliato chiamare quelle cose normalizzazione.

Oh, e quella tabella a due colonne che ho fornito sopra - è in 5NF.


2
Ben fatto. Sono stato tentato di pubblicare una risposta che non dicesse altro che la tua prima frase ... "L'altro progettista di database ha semplicemente torto", hai spiegato molto bene il perché.
Mark Storey-Smith,

5

La creazione di una tabella separata per qualsiasi attributo non ha nulla a che fare con la normalizzazione. 2NF, 3NF, BCNF, 4NF, 5NF sono tutti interessati all'eliminazione delle dipendenze non chiave. Se rimuovi un singolo attributo in una nuova tabella e lo sostituisci con un attributo di chiave esterna, le dipendenze nella tabella saranno logicamente le stesse di prima - quindi la versione rivista della tabella non è più o meno normalizzata di essa era prima.


Voglio aggiungere qualcosa a questo, ma non so cosa. Stai dicendo che spostare qualcosa in una tabella che ha una correlazione 1: 1 (1 chiave esattamente su 1 valore come in questo caso o una riga su una riga) non dà alcun vantaggio se la ricerca non è necessaria, giusto? Ma c'è un potenziale vantaggio nella ricerca se raramente hai bisogno dell'anno e stai guardando solo un intervallo di 255 anni o meno. Si potrebbe presumibilmente cavarsela con alcuni byte salvati qui, ma dal momento che normalmente questi sono allocati a 4 byte, questo non è un presupposto ragionevole.
jcolebrand

1
@jcolebrand: d'accordo con quello che dici. Tuttavia la risposta alla domanda è la stessa: se lo fai o no non ha nulla a che fare con la normalizzazione in sé.
nvogel,

Concordo. Come ho detto, il mio era una specie di indifeso "Sento che qui all'OP manca qualcosa" ... perché non sono sicuro di dove andare con questo concetto.
jcolebrand

5

Dal mio punto di vista, una tabella annuale separata avrebbe senso solo se l '"anno di uscita" non è un anno solare, ma ad esempio un anno fiscale che potrebbe estendersi su più anni civili (ad esempio, da ottobre a ottobre).

La tabella conterrebbe quindi la definizione (data di inizio e fine effettive) dell'anno fiscale


1
+1 hai bisogno di un tavolo solo se avrà attributi :)
Jack Douglas,

2

Da http://en.wikipedia.org/wiki/Second_normal_form :

una tabella 1NF è in 2NF se e solo se, data una chiave candidata K e qualsiasi attributo A che non è un componente di una chiave candidata, A dipende dall'intera K piuttosto che solo da una sua parte.

Non hai indicato se l'anno fa parte o meno della chiave candidata, ma non sono sicuro che contenga, perché in entrambi i casi 2NF sarebbe soddisfatto per quanto riguarda l'anno.

A livello pratico è una cattiva idea separare l'anno per tutti i motivi elencati.


2

Non mi piace l'argomento contro la tabella separata a causa delle sue dimensioni o che avrà righe inutilizzate. Anche se metti 1000 anni in questa tabella, la dimensione sarà trascurabile.

Detto questo, non credo che il tavolo sia affatto necessario. Qual è il punto di avere un tavolo separato per l'anno? Questi dati sono già nella tabella principale e non si salva assolutamente nulla creando una seconda tabella.

L'argomento può essere diverso per una tabella di calendario, in cui ogni riga rappresenta un giorno e può avere altri attributi (giorno della settimana, offset UTC, che si tratti di una vacanza, ecc.).

Ma solo l'anno? No, non vedo alcun beneficio ... E come altri hanno sottolineato, chiedi loro perché pensano che sia più normalizzato? O cosa guadagnano? Se stai cercando di scrivere query come

WHERE othertable.year = 2011

Invece di

WHERE dt >= 20110101 AND dt < 20120101

Quindi proverei a convincerti che quest'ultimo è molto meglio per prestazioni (supponendo che dt sia indicizzato) e archiviazione. Se la semplicità di codifica è fondamentale, direi che una colonna calcolata persistente sarebbe migliore di un'altra tabella.


1

Sono totalmente d'accordo con la risposta di Catcall tranne che su un punto: "anno" potrebbe non essere sempre un valore primitivo, ma immagino che sia più un concetto di logica aziendale che uno di progettazione di database.

Mantenendo lo stesso design, supponiamo che gli anni debbano essere solo quelli che possono essere rilasciati. In tal modo, non hai a che fare con valori numerici primitivi, ma piuttosto con un loro sottoinsieme, e poiché tale sottoinsieme non ha un'implementazione primitiva, devi fare il tuo (una tabella separata?) E fare riferimento a esso (con un FK). In tal modo, stiamo ancora parlando di anni, ma dobbiamo gestirli in modo diverso, perché hanno cambiato concettualmente il loro significato. Tuttavia, sono ancora "anni di rilascio", ma concettualmente diversi in termini di cosa significano per qualcuno con conoscenza del dominio.

Per questo caso specifico, dico ancora una volta che la risposta di Catcall è corretta, ma volevo solo sottolinearlo. (Mi dispiace, non ho ancora abbastanza rappresentante per commentare.)

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.