<div class="page"> <div class="cover text-center"> <img class="mx-auto" src=/itb/images/logo_mislata.png alt="logo"> # Normalització <div class="text-end fit-content ms-auto my-3 mt-auto pt-3"> <p><strong>Autor:</strong> Joan Puigcerver Ibáñez</p> <p><strong>Correu electrònic:</strong> j.puigcerveribanez@edu.gva.es</p> <p><strong>Curs:</strong> 2023/2024</p> </div> <div> <p class="fw-bold mb-0">Llicència: BY-NC-SA</p> <p class="d-none d-md-block">(Reconeixement - No Comercial - Compartir Igual)</p> <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ca" target="_blank"> <img class="mx-auto" src="/itb/images/license.png" alt="Licence"/> </a> </div><!--license--> </div><!--cover--> </div><!--page--> {:toc} ## Introducció La normalització en les bases de dades relacionals és un procés de disseny que s'utilitza per a organitzar i estructurar les dades de manera eficient, on l'objectiu principal és reduir la redundància i millorar la integritat de les dades. Si és necessari aplicar la normalització, significa que el model d'entitat relació, o la transformació a model relacional no s'ha fet correctament i existeixen atributs redundants; per tant, serveix per a corregir allò que no ha sigut correctament dissenyat. ## 1NF: Primera Forma Normal La __Primera Forma Normal (1NF)__ especifica que les taules no poden contindre valors repetits i que totes les cel·les d'una taula han de contindre valors atòmics. Un atribut és __atòmic__ si i sols si no es pot dividir en altres atributs, per tant, no es permeten __atributs compostos__. La millor manera d'evitar valors repetits és definint una __clau primària__. L'objectiu d'aquesta normalització és augmentar la flexibilitat i la independència de les dades, i simplificar la definició d'aquestes. També obri la porta a una normalització addicional, que elimina la redundància i les anomalies. La majoria de SGBD relacionals no suporten registres ennierats (_nested_), per tant, les taules estan en primera forma normal per defecte. ::: example "Exemple 1NF" En el cas de la taula **[PERSONA]{.blue}([#dni]{.red}, nom, cognom, data_naixement, telefons)**, podríem trobar els següents valors: | Taula Persona ||||| | #DNI | Nom | Cognoms | Data Naixement | Telèfons | | :- | :- | :- | :- | :- | | __91471118A__{.green} | Carles | Perelló | 08/12/2000 | [643857623, 638741285, 669852237]{.red} | | __23986973C__{.yellow} | Òscar | Peris | 02/01/2001 | 687418459 | | __24211153L__{.orange} | Andreu | Pastor | 02/04/2001 | 602145235 | | __76064612R__{.blue} | Isabel | Mora | 28/11/2001 | [674125596, 632147852]{.red} | {.center} Es pot observar que la columna __Telèfons__ emmagatzema múltiples valors i, per tant, aquesta taula no està en __Primera Forma Normal__. La solució és crear una taula relacional addicional: <div class="d-flex justify-content-evenly flex-wrap flex-wrap"> | Taula Persona ||||| | #DNI | Nom | Cognoms | Data Naixement | | :- | :- | :- | :- | | __91471118A__{.green} | Carles | Perelló | 08/12/2000 | | __23986973C__{.yellow} | Òscar | Peris | 02/01/2001 | | __24211153L__{.orange} | Andrès | Pastor | 02/04/2001 | | __76064612R__{.blue} | Isabel | Mora | 28/11/2001 | | Taula Telefon_Persona ||||| | _#DNI_ | #Telèfon | | :- | :- | :- | :- | :- | | __91471118A__{.green} | 643857623 | | __91471118A__{.green} | 638741285 | | __91471118A__{.green} | 669852237 | | __23986973C__{.yellow} | 687418459 | | __24211153L__{.orange} | 602145235 | | __76064612R__{.blue} | 674125596 | | __76064612R__{.blue} | 632147852 | ::: </div> ## 2NF: Segona Forma Normal Es diu que una taula relacional està en __Segona Forma Normal (2NF)__ quan està en 1NF, i a més, tots els atributs que no siguen cap clau tenen una __dependència funcional completa__ cap a la __clau primària__. Es defineix com __dependència funcional__ la relació entre dos atributs en una taula relacional, que defineix la manera en què els valors d'una columna determinen de manera única els valors d'una altra. Hi ha dos tipus: - __Dependència Funcional Completa__: - Un atribut Y es diu que està totalment dependent funcionalment de l'atribut $X$ en una taula si, per a cada valor de $X$, només hi ha un valor corresponent de $Y$. - En altres paraules, donat un valor específic de $X$, pots determinar de manera única el valor de $Y$. - Això sol representar-se com $X → Y$. - __Dependència Funcional Parcial__: - Un atribut Y es diu que està parcialment dependent funcionalment de l'atribut $X$ en una taula si, per a alguns valors de $X$, hi ha més d'un valor corresponent de $Y$. - En aquest cas, la dependència és parcial, ja que no tots els valors de Y es poden determinar per $X$. - Les dependències funcionals parcials poden provocar anomalies de dades i, generalment, no són desitjables. ::: example "Exemple Dependència Funcional" En el cas de la taula **[PERSONA]{.blue}([#dni]{.red}, nom, cognom, data_naixement)**. - __Dependència Funcional Completa__: $dni \rightarrow nom$ Donat un DNI sempre pots determinar el nom de la persona. - __Dependència Funcional Parcial__: $data\_naixement \rightarrow nom$ Donada una data de naixement no pots identificar de manera única al nom d'una persona, ja que múltiples persones amb un mateix nom poden tindre dates de naixement diferents. ::: ::: example "Exemple 2NF" En la taula **[DETALLS_COMANDA]{.blue}([#id_comanda]{.red}, [#producte]{.red}, preu_producte, unitats)** podríem trobar els següents valors: | Taula Detalls Comanda ||||| | #ID Comanda | #Producte | Preu Producte | Unitats | | :- | :- | :- | | __1__{.red} | __Barra de pa__{.red} | 0.7 | 2 | | __1__{.red} | __Botella aigua 0.5L__{.green} | 0.3 | 1 | | __2__{.green} | __Botella aigua 0.5L__{.green} | 0.3 | 1 | | __2__{.green} | __Pot Coca-Cola 33 cL__{.yellow} | 1.5 | 1 | | __2__{.green} | __Napolitana xocolate__{.blue} | 1.5 | 2 | {.center} Aquesta taula està en 1NF, però, no obstant això, podem determinar que no està en 2NF, ja que l'atribut `preu_producte`, no té una dependència funcional completa cap a la clau primària `(id_comanda, producte)`, però sí cap a `producte`. És a dir, el preu del producte no depén de la comanda. Per solucionar-ho, podem separar la informació en dues taules relacionals: <div class="d-flex justify-content-evenly flex-wrap flex-wrap"> | Taula Producte||||| | #Producte | Preu | | :- | :- | :- | | __Barra de pa__{.red} | 0.7 | | __Botella aigua 0.5L__{.green} | 0.3 | | __Pot Coca-Cola 33 cL__{.yellow} | 1.5 | | __Napolitana xocolate__{.blue} | 1.5 | | Taula Detalls Comanda ||||| | #ID Comanda | #_Producte_ | Unitats | | :- | :- | :- | | __1__{.red} | __Barra de pa__{.red} | 2 | | __1__{.red} | __Botella aigua 0.5L__{.green} | 1 | | __2__{.green} | __Botella aigua 0.5L__{.green} | 1 | | __2__{.green} | __Pot Coca-Cola 33 cL__{.yellow} | 1 | | __2__{.green} | __Napolitana xocolate__{.blue} | 2 | </div> ::: ## 3NF: Tercera Forma Normal Es diu que una taula relacional està en __Tercera Forma Normal (3NF)__ quan està en 2NF, i a més, i que cap atribut no primari és transitivament dependent de la clau primària. Donats els atributs $A$, $B$, i $C$, es diu que $C$ és transitivament dependent de $A$ si: - $A \rightarrow B$: $B$ té una dependència funcional completa amb $A$. - $B \rightarrow C$: $C$ té una dependència funcional completa amb $B$. $$A \rightarrow B \rightarrow C$$ ::: example "Exemple 3NF" En la taula **[TORNEIG]{.blue}([#nom]{.red}, [#edicio]{.red}, guanyador, data_naixement_guanyador)** podríem trobar els següents valors: | Taula Torneig||||| | #Nom | #Edició | Guanyador | Data Naixement Guanyador | | :- | :- | :- | :- | | Roland Garros | 2020 | Rafael Nadal | 03/06/1986 | | Roland Garros | 2021 | Novak Đoković | 22/05/1987 | | Roland Garros | 2022 | Rafael Nadal | 03/06/1986 | | Roland Garros | 2023 | Novak Đoković | 22/05/1987 | | Wimbledon | 2021 | Novak Đoković | 22/05/1987 | | Wimbledon | 2022 | Novak Đoković | 22/05/1987 | | Wimbledon | 2023 | Carlos Alcaraz | 05/05/2003 | {.center} Aquesta taula està en 2NF, ja que es pot justificar que tots els atributs no primaris depenen d'una manera funcionalment completa de la clau primària. No obstant això, l'atribut `data_naixement_guanyador` depén de l'atribut `guanyador`, on aquest depén de la clau primària (`nom`, `edicio`), per tant, l'atribut `data_naixement_guanyador` té una dependència transitiva amb la clau primària. $$ (nom, edicio) \rightarrow guanyador \rightarrow data\_naixement\_guanyador $$ Per solucionar-ho, hem de separar la informació en dues taules relacionals: <div class="d-flex justify-content-evenly flex-wrap flex-wrap"> | Taula Torneig ||||| | #Nom | #Edició | _Guanyador_ | | :- | :- | :- | :- | | Roland Garros | 2020 | __1__{.red} | | Roland Garros | 2021 | __2__{.green} | | Roland Garros | 2022 | __1__{.red} | | Roland Garros | 2023 | __2__{.green} | | Wimbledon | 2021 | __2__{.green} | | Wimbledon | 2022 | __2__{.green} | | Wimbledon | 2023 | __3__{.blue} | | Taula Jugador ||||| | #ID | Nom | Data Naixement | | :- | :- | :- | :- | | __1__{.red} | Rafael Nadal | 03/06/1986 | | __2__{.green} | Novak Đoković | 22/05/1987 | | __3__{.blue} | Carlos Alcaraz | 05/05/2003 | </div> ::: ## BCNF: Forma Normal de Boyce-Codd Una taula està en __Forma Normal de Boyce-Codd (BCNF)__ si i sols si està en 3NF i totes les relacions de dependència funcional depenen de la clau primària. Aquesta forma normal no és molt comuna, però apareix quan hi ha diferents claus candidates que haurien pogut esdevindre claus primàries i se solapen, és a dir, tenen almenys un atribut comú. Una relació formada pels atributs $A$, $B$, $C$ i $D$ on hi ha dues claus candidates compostes $(A, B)$ i $(B, C)$ i existeix una dependència funcional en els dos sentits entre $A$ i $C$, $(A \longleftrightarrow C)$, pot ser modelada de dues maneres: - $R1(A, C)$ i $R2(A, B, D)$ - $R1(A, C)$ i $R2(C, B, D)$ La relació $R(A, B, C, D)$ no estaria en BCNF. ::: example La taula **[CONDUCTOR_COTXE]{.blue}(++[#matricula]{.red}++, n_bastidor, ++_[#dni_conductor]{.red}([PERSONA]{.blue}:[#dni]{.red})_++, data_inici)** podríem trobar els següents valors: | Taula Conductor Cotxe ||||||| | ++#Matrícula++ | N. Bastidor | ++_#DNI Conductor_++ | Data inici | | :- | :- | :- | :- | :- | :- | :- | | __4231 KJL__{.red} | [16483920]{.red} | __91471118A__{.green} | 08/12/2000 | | __4231 KJL__{.red} | [16483920]{.red} | __24211153L__{.orange} | 02/01/2001 | | __4078 CMP__{.green} | [23948756]{.green} | __91471118A__{.green} | 02/04/2001 | | __4078 CMP__{.green} | [23948756]{.green} | __23986973C__{.red} | 28/11/2001 | | __3091 LSF__{.orange} | [12347003]{.orange} | __23986973C__{.red} | 05/12/2001 | | __3091 LSF__{.orange} | [12347003]{.orange} | __24211153L__{.orange} | 05/12/2001 | {.center} Aquesta taula està en 3NF, però no en BCNF. En aquest cas, existeixen dues claus candidates `matricula` i `n_bastidor`, que poden ser utilitzades indistintament com a clau primària ($matricula \longleftrightarrow n\_bastidor$). Per tant, existeixen les relacions: - $(matricula, conductor) \rightarrow data\_inici$ - $(n\_bastidor, conductor) \rightarrow data\_inici$ Per evitar la redundància de dades i determinar que totes les relacions de dependència han de dependre de la clau primària, podem eliminar les claus candidates que no formen part de la clau primària i emmagatzemar-les en una altra relació. <div class="d-flex justify-content-evenly flex-wrap flex-wrap"> | Taula Conductor Cotxe ||||||| | ++#Matrícula++ | ++_#DNI Conductor_++ | Data inici | | :- | :- | :- | :- | :- | :- | :- | | __4231 KJL__{.red} | __91471118A__{.green} | 08/12/2000 | | __4231 KJL__{.red} | __24211153L__{.orange} | 02/01/2001 | | __4078 CMP__{.green} | __91471118A__{.green} | 02/04/2001 | | __4078 CMP__{.green} | __23986973C__{.red} | 28/11/2001 | | __3091 LSF__{.orange} | __23986973C__{.red} | 05/12/2001 | | __3091 LSF__{.orange} | __24211153L__{.orange} | 05/12/2001 | | Taula Cotxe ||||||| | ++#Matrícula++ | N. Bastidor | :- | :- | | __4231 KJL__{.red} | [16483920]{.red} | | __4078 CMP__{.green} | [23948756]{.green} | | __3091 LSF__{.orange} | [12347003]{.orange} | </div> ::: ## 4NF: Quarta Forma Normal Una taula està en __Quarta Forma Normal (4NF)__ si i sols si està en 3NF o BCNF (qualsevol de les dues) i no existeixen __dependències multivaluades__. Una __dependència multivaluada__ es dona en relacions on hi ha almenys tres atributs ($A$, $B$ i $C$) que formen part de la clau primària de la relació i per a un valor donat de $A$ existeix un conjunt de valors ben definit dels atributs $B$ i $C$, però $B$ i $C$ són independents entre ells. Podeu consultar la definició formal a: https://en.wikipedia.org/wiki/Multivalued_dependency ::: example "Exemple 4NF" En la taula **[RESTAURANT_TIPUSPIZZA_AREAENVIAMENT]{.blue}(++[#restaurant]{.red}++, ++[#tipus_pizza]{.red}++, ++[#area_enviament]{.red}++)** podríem trobar els següents valors: | Taula Restaurant / Tipus Pizza / Àrea Enviament ||||||| | ++#Restaurant++ | ++#Tipus Pizza++ | ++#Àrea Enviament++ | | :- | :- | :- | | Vincenzo's Pizza | Vora grossa | Russafa | | Vincenzo's Pizza | Vora grossa | Mislata | | Vincenzo's Pizza | Vora fina | Russafa | | Vincenzo's Pizza | Vora fina | Mislata | | Elite Pizza | Vora fina | Universitats | | Elite Pizza | Vora farcida | Universitats | | A1 Pizza | Vora grossa | Russafa | | A1 Pizza | Vora grossa | Mislata | | A1 Pizza | Vora grossa | Universitats | | A1 Pizza | Vora farcida | Russafa | | A1 Pizza | Vora farcida | Mislata | | A1 Pizza | Vora farcida | Universitats | {.center} Cada fila indica que un restaurant concret pot entregar un tipus de pizza donat en una zona donada, el que podria constituir una relació ternària. Aquesta taula està en FNBC, ja que sols conté una clau primària única i no té cap atribut no-clau. No obstant això, si la varietat de la pizza és independent de l'àrea d'enviament, existeix una dependència multivaluada i una redundància de les dades. Si _A1 Pizza_ comença a produir pizzes del tipus _Vora de formatge_, hem d'afegir un registre per cada àrea d'enviament. Per satisfer la 4NF cal separar cada relació en una taula: <div class="d-flex justify-content-evenly flex-wrap flex-wrap"> | Taula Restaurant / Tipus Pizza ||||| | ++#Restaurant++ | ++#Tipus Pizza++ | | :- | :- | | Vincenzo's Pizza | Vora grossa | | Vincenzo's Pizza | Vora fina | | Elite Pizza | Vora fina | | Elite Pizza | Vora farcida | | A1 Pizza | Vora grossa | | A1 Pizza | Vora farcida | | Taula Restaurant / Àrea Enviament ||||||| | ++#Restaurant++ | ++#Àrea Enviament++ | | :- | :- | :- | | Vincenzo's Pizza | Russafa | | Vincenzo's Pizza | Mislata | | Elite Pizza | Universitats | | A1 Pizza | Russafa | | A1 Pizza | Mislata | | A1 Pizza | Universitats | </div> No obstant això, si les varietats de pizza que poden ser oferides per un restaurant varien dependent de l'àrea d'enviament, la taula original sí que satisfaria la 4FN. ::: ## 5NF: Quinta Forma Normal Una taula està en __Quinta Forma Normal (5NF)__, també coneguda com la __Forma Normal de Projecció-Unió (PJ/NF)__, si i sols si està en 4NF i cada __dependència d'unió__ en ella està implicada amb claus candidates i no existeixen restriccions imposades per la base de dades. - Explicació i exemple: [Quinta Forma Normal - Wikipedia](https://es.wikipedia.org/wiki/Quinta_forma_normal) ## Desnormalització El procés de __normalització__ implica la creació de taules relacionals addicionals per evitar la redundància de dades, però pot afectar el rendiment de les bases de dades, ja que el motor de bases de dades ha de relacionar i combinar els valors de moltes taules per realitzar les consultes. El procés de __desnormalització__ consisteix en la duplicació intencionada de les dades per evitar crear moltes taules addicionals i afectar el rendiment i la complexitat del disseny de la base de dades. Normalment, es busca un equilibri entre buscar que la redundància de dades siga mínima, sense afectar massa el rendiment de la base de dades. Un bon nivell per parar està entre 3NF, BCNF i 4NF, encara que està bé considerar totes les possibilitats i triar entre els dissenys resultants. - https://stackoverflow.com/questions/2065227/when-is-a-good-time-to-break-normalization-rules - https://stackoverflow.com/questions/12327859/what-is-the-best-normal-form-in-large-scale-system ## Bibliografia - Ahijado Sánchez, A, _Bases de datos_, Ed. Marcombo. - https://en.wikipedia.org/wiki/First_normal_form - https://es.wikipedia.org/wiki/Tercera_forma_normal - https://es.wikipedia.org/wiki/Forma_normal_de_Boyce-Codd - https://en.wikipedia.org/wiki/Fourth_normal_form - https://en.wikipedia.org/wiki/Multivalued_dependency - https://en.wikipedia.org/wiki/Denormalization