Normalisointi
Luvussa käsitellään tietokantojen normalisointisääntöjä, jotka tulisi tuntea tietokantasuunnittelun vuoksi. Normalisointisäännöt ohjaavat kohti hyvää tietokantaratkaisua.
Last updated
Luvussa käsitellään tietokantojen normalisointisääntöjä, jotka tulisi tuntea tietokantasuunnittelun vuoksi. Normalisointisäännöt ohjaavat kohti hyvää tietokantaratkaisua.
Last updated
Lyhyesti sanottuna normalisointi (eng. normalization) tarkoittaa tietokantasuunnitteluun liittyviä tekniikoita, joiden tarkoitus on minimoida tiedon toistuvuutta ja riippuvuutta. Säännöt keskittyvät oleellisesti tietokantataulujen sisältöihin.
Noudattamalla sääntöjä ne ohjaavat siihen, että suuri taulu saadaan pilkottua pienemmiksi tauluiksi sekä luomaan näiden välille riippuvuussuhteita. Kts. Pää- ja viiteavaimet. Lopputuloksena tietokannassa oleva tieto on siis selkeämmin järjestetty. Terminä normalisointi viittaakin tietokannan rakenteisiin .
Erilaisia normaalimuotoja on yhteensä kuusi kappaletta mutta pääasiassa kolme ensimmäistä on tärkeintä. Kolmannen jälkeen ei aina saada suuria hyötyjä mutta hyvä tapa on yrittää noudattaa kolmea ensimmäistä. Sääntöjen noudattaminen tarkoittaa myös, että toteuttaakseen esimerkiksi kolmannen normaalimuodon pitää sen hetkisen ratkaisun toteuttaa myös kaksi edellistä normaalimuotoa.
Kun tietokannassa on huomioitu nämä säännöt niin voidaan lyhyesti aina ilmaista esimerkiksi, että tietokantamalli on 3. normaalimuodon mukainen. Tämä jo heti antaa viitteen sille minkälainen tietokanta on kyseessä. Aina näin ei ole ja suunnitteluvirheet johtavat erilaisiin ongelmiin tiedon käsittelyn kanssa.
Normalisoinnin lisäksi voidaan puhua denormalisoinnista (eng. denormalization), joka tarkoittaa sääntöjen rikkomista. Tämä tehdään usein hyvästä syystä ja perustellen. Ei siksi, että sääntöjä ei noudatettaisi vaan sillä voidaan joissain tilanteissa nostaa esimerkiksi suorituskykyä.
Tietokannan normalisoinnin taustalla on Edgar Codd, joka on esitellyt ja määritellyt ensimmäiset kolme sääntöä. Tutustutaan seuraavaksi kolmeen ensimmäiseen normaalimuotoon syvemmin.
Normalisointisäännöt tullaan esittämään esimerkin kautta. Ensimmäisenä esittelemme normalisoimattoman taulun, josta esimerkit syntyvät. Tietokantamalli ei voi toteuttaa seuraavaa normaalimuotoa ellei se toteuta myös edellisiä normaalimuotoja.
On mahdollista, että oikean tiedon kanssa tietyissä olosuhteissa normalisointisäännöt eivät toteudu tai ne niiden yli voidaan hypätä. Esimerkki on kuitenkin tehty siitä näkökulmasta, että erilaiset tilanteet tulevat vastaan. Tietokantamallina toimii seuraavanlainen tv-sarjoja sisältävä tietokantataulu.
Yllä oleva malli esittää yhden esimerkkirivin millaista tietoa taulu sisältää. Kun tietoa ei ole tallennettu oikealla tavalla, tuottaa se usein ongelmia. Tiedon lisääminen, muokkaaminen ja poistaminen osoittautuu yleensä hankalaksi. Ensimmäiseksi tarkastelemme esimerkkiä 1. normaalimuodon määrittelemällä tavalla.
Ensimmäinen normaalimuoto on tosi, jos:
jokainen taulun sarake sisältää yhden arvon.
jokainen taulun rivi on uniikki.
Englanninkielisissä lähteissä puhutaan termillä atomic value. Sillä tarkoitetaan arvoa, jota ei voi enää jakaa pienempiin osiin.
Kun tarkastellaan esimerkin taulua televisiosarjat niin on melko selkeää, ettei se vastaa ensimmäistä sääntöä lainkaan. Pelkästään esimerkin tiedot paljastavat toistuvat arvot. Katsotaan esimerkkinä sarake luojat, joka sisältää kaksi nimeä: David Benioff ja D.B. Weiss. Lähestulkoon aina sarake, jossa on kokoelma tietoa niin voidaan pilkkoa. Jotta pääsemme kohti 1. normaalimuotoa niin ratkaisu tähän on pilkkoa kenttä omaan tauluunsa. Luodaan siis taulu luojat.
Nyt tilanne ei vielä ole muuttunut paremmaksi. Taulujen välillä ei ole liitosta ja uusi luojat -taulu ei sisällä pääavainta. Jos mietimme ensin pääavainta niin valintamme voisi olla jokin seuraavista:
Juokseva numerointi (1,2,3,4,5....)
Jokin luonnollinen yhdistelmä sarakkeita, kuten esimerkiksi sarjan tunniste ja henkilön nimi.
Koska taulujen välillä ei ole minkäänlaista suhdetta niin voimme vielä miettiä, että mikä sen kuuluisi olla. Kun tiedämme, että alkuperäisessä sarakkeessa on ollut kaksi arvoa niin voimme päätellä, että yhdellä tv-sarjalla on yksi tai useampi luoja. Voimme tarkastella aina myös muita taulun rivejä, josta voisimme päätellä lisää mutta tässä kohdin tiedämme, että luojia voi olla useita mutta usein vähintään yksi. Tottakai tilanne, jossa luojaa ei tiedetä on aivan mahdollinen. Muotoillaan suhde seuraavasti:
Tv-sarjalla voi olla useita luojia tai ei yhtään.
Tämän perusteella saattaisimme päästä seuraavanlaiseen taulujen suhteeseen. Esimerkki sisältää jo kentät edellä olevan suhdetyypin luomiselle. Alla olevassa kuvassa taulu televisiosarjat on liitetty luojat -tauluun. Kuvassa ei näy suhteen tyyppiä mutta se on aiemmin kuvatun mukainen. (Suhteiden kuvaamistavasta on oma lukunsa). Televisiosarjat -taulusta huomaamme, että siitä puuttuu nyt kokonaan luojat -sarake. Sarakkeen tietojen perusteella on siis luotu kokonaan oma taulunsa. Huomaamme myös, että luojat -taulun pääavaimena toimii nyt sen kaksi saraketta. Palaamme tähän vielä myöhemmin.
Alla näemme esimerkit tämän ensimmäisen kohdan normalisoinnin jälkeen eli miten tieto on esitetty luojat -taulussa. Luojat taulussa siis viitataan televisiosarjat -riviin sen tunnisteella (id).
Luojat -taulun pääavain ei ole vielä kovin järkevät mutta asioita usein tehdään yksi kerrallaan. Pääavaimessa on kuitenkin se etu, että henkilöä ei voi nyt lisätä toiseen kertaan samaan tv-sarjaan luojaksi mikäli rivi on jo olemassa. Mysql antaa seuraavanlaisen virheen kun pääavaimen ehdot eivät täyty:
#1062 - Duplicate entry '1-David Benioff' for key 'PRIMARY'
Pääsääntöisesti tässä on kyse 1. normaalimuodon toteutumisesta eli jokainen tällainen sarake, joka sisältäisi useita arvoja niin tulee käsitellä. Usein ratkaisu on juurikin toinen taulu mutta taulujen väliset suhteet voivat vaihdella tiedon sisällön mukaan. Tehdään vielä toinen vastaava esimerkki käyttäen tvkanavat -saraketta. Kun noudatamme samanlaista sääntöä niin lopputulos voisi olla seuraavanlainen.
Molemmissa tilanteissa tvsarja_id -sarake viittaa televisiosarjat -taulun pääavaimeen. Tällöin siis tvsarja_id -sarake toimii viiteavaimena. Tähän tapaan jatkettaisiin muiden tietojen kohdalla. Kaikkia ei käydä läpi yksitellen, koska vastaavia sarakkeita on esimerkissä paljon. Nyt siis taulut eivät vielä täysin toteuta 1. normaalimuotoa mutta jatkamalla loppuun asti samalla tapaa, näin tulisi käymään. Esimerkissämme siirrymme 2. normaalimuotoon.
Taulussa voisi olla myös tilanne missä olisi sarakkeet: paaosa_01, paaosa_02, paaosa_03 jne. Tällaiset sarakkeet kertovat myös huonosta suunnittelusta, koska ovat samalla tavoin arvoja, joita on useita vaikka eivät yhdessä sarakkeessa olekaan. Ongelma on myös, että joudumme aina muuttamaan tietokantarakennetta, jos tietojen määrä kasvaa. Tähän tulisi myös noudattaa 1. normaalimuodon sääntöä.
Toinen normaalimuoto on tosi, jos:
ensimmäinen normaalimuoto on tosi.
kaikki sarakkeet ovat täysin riippuvia koko pääavaimesta, poislukien avaimet.
Nykyinen esimerkkimme on 2. normaalimuodon osalta huono. Televisiosarjat -taulu sisältää pääavaimen, joka koostuu yhdestä sarakkeesta niin tällöin kaikki muut sarakkeet ovat riippuvaisia siitä. Toinen normaalimuoto korostuu erityisemmin silloin kun taulun pääavain koostuu useammasta sarakkeesta. Tämän esimerkin vuoksi muutamme hieman tvkanavat -taulua seuraavanlaiseksi.
Kuvan mukaisessa tilanteessa tvkanavat -taulu sisältää nyt uuden pääavaimen, joka koostuu tvsarja_id ja kanavan_id -sarakkeesta. Kun nyt tarkastelemme kanavan nimeä niin voimme miettiä riippuuko se koko pääavaimesta. Nimi riippuu selkeästi kanavan tunnisteesta (kanavan_id) arvosta. Kun taas TV-sarjan tunniste muuttuu niin sillä ei ole mitään yhteyttä kanavan nimeen.
Tällaisessa tilanteessa huomaamme, että kanavan_nimi -sarake ei riipu molemmista pääavaimen sarakkeista mutta sen arvo myös toistuu. Jos kanavan tunniste vaihtuu niin kuuluisi muistaa päivittää vielä kanavan nimi sekä muut toistuvat tiedot. Kuvattu tilanne usein tarkoittaa, ettei taulu toteuta 2. normaalimuotoa. Näissä tilanteissa tiedot pitää myös purkaa omaan tauluun. Esimerkin tilanteessa voimme saada aikaiseksi seuraavan tietokantarakenteen:
Tv-kanavat taulu muuttui siten, että tv-sarjan tunniste poistettiin. Tällöin sisältö vastaa paremmin taulun sisältöä muutenkin eli se sisältää tv-kanavien tietoja. Muutoksen myötä kadottaisimme tiedon siitä missä tv-kanavissa kyseistä sarjaa on esitetty. Tätä varten voidaan luoda usein liitostaulu, joka yhdistää nämä asiat. Esimerkissämme olemme siis luoneet televisiosarjat_tvkanavat -nimisen taulun, jossa on vain tunnisteet.
Jos nyt päivittäisimme TV-kanavan tietoja niin sisältö pysyy ajantasaisena. Koska kanavia voi olla useita yhtä tv-sarjaa kohden niin kyseessä on monen suhde moneen -liitos.
Samankaltainen tilanne saattaisi tulla vastaan luojat -taulun kanssa. Kun taas mietimme tietokannan sisältöä niin tällaiset suhteet voitaisiin pystyä huomaamaan jo tietokannan suunnittelun aikana ja siten suunnitella etukäteen. Toisinaan taas yhteydet huomataan myöhemmin kun oikeaa tietoa saadaan luotua. Usein tietojen suhteet keskenään eivät ole selviä kuten aina esimerkeissä.
Kolmas normaalimuoto on tosi, jos:
toinen normaalimuoto on tosi.
sisältää sarakkeita, jotka eivät ole transitiivisesti riippuvaisia taulun pääavaimesta.
Transitiivisella riippuvuudella tarkoitetaan sitä, että sarake A on riippuvainen sarakkeesta B jonkun toisen sarakkeen kautta. Käytännössä sarake A on transitiivisesti riippuvainen sarakkeesta B, jos sarake A on riippuvainen sarakkeesta C, joka on riippuvainen sarakkeesta B. Tässä A, B ja C voivat sisältää myös useampia sarakkeita.
Esimerkkiä varten keskitymme televisiosarjat -taulun tyylit -sarakkeeseen. Yksinkertaisuuden vuoksi olemme luoneet taas tilanteen missä tauluun on lisätty sarake tyyli_id. Alla on kuva tilanteesta, jossa ei näy kaikkia sarakkeita taulusta.
Kun tarkastelemme taulua nyt 3. normaalimuodon ehdoilla niin voimme ilmaista asian seuraavasti. Sarakkeet tyyli (tv-sarjan kategoria tai tyylilaji) ja tyyli_id ovat molemmat riippuvaisia pääavaimesta. Se siis määrittää tyylilajin. Mainitut kaksi saraketta eivät kuitenkaan ole toisistaan riippumattomia. Tyylilaji voidaan tässä päätellä tyylilajin tunnisteen perusteella. Tv-sarjoja on olemassa vielä useampia kuin tyylilajeja, joten tämä aiheuttaa myös tiedon toistuvuutta televisiosarjat -taulussa.
Kun edellä mainitun oloinen tilanne kohdataan, ratkaisu on jälleen kerran helppo. Tiedot tulisi siirtää omaan tauluunsa. Tämän perusteella voimme siis päästä seuraavanlaiseen tietokantaratkaisuun.
Televisiosarjat -tauluun jäi siis vain tyylilajin tunniste (sarake myös uudelleen nimetty) ja tyylilaji erotettiin omaksi taulukseen. Televisiosarja -taulusta viitataan tyylilajeihin ja tyylilajit -taulu ei sisällä tv-sarjan tunnistetta. Tällöin voidaan puhua, että puhutaan yksi suhde yhteen -liitoksesta taulujen välissä. Taulujen sisältämä tieto näyttää nyt vielä seuraavalta.
Esimerkissämme jätämme normaalimuotojen käsittelyn tähän. Usein 3. normaalimuoto on hyvä tavoite ja työmäärä tai hyöty seuraavista vaiheista ei aina maksa itseään takaisin. Perusteina on hyvä tuntea nämä kolme ensimmäistä. Normaalimuotojen tunnistaminen on usein haastavaa ja siksi kannattaa katsoa myös alla olevista lähteistä lisää tietoja ja esimerkkejä miten nämä on kerrottu muiden esimerkkien avulla.
Kertaamme vielä miksi normalisointi on tärkeä aihe tietokantasuunnittelussa. Se sopii myös hyvin erilaisiin tietokantaratkaisuihin tarvittaessa vaikka onkin alunperin suunniteltu relaatiotietokantojen suunnitteluun.
Tavoitteet lyhyesti:
Luoda sellaiset suhteet tietojen välille, että vältytään ei-toivottujen lisäys, muokkaus tai poisto komentojen riippuvuuksista.
Vähentää taulujen rakenteiden muuttamista tilanteissa, jossa esitellään uusia tietoja sekä kasvattaa rakenteen elinkaarta.
Tehdäkseen taulujen välisistä suhteista ja sen sisältämästä tiedosta ymmärrettävämpää käyttäjille.
Niin sanottuja ei-toivottuja riippuvuuksia tiedon muuttamisen kohdalla ovat pääasiassa seuraavat tilanteet, jotka esiintyvät mahdollisesti huonosti normalisoidun tietokannan kohdalla.
Tiedon lisäämisen yhteydessä - Uutta tietoa ei voida luoda ilman, että sille luodaan jokin muu riippuvuus mitä ei välttämättä ole olemassa. Esimerkkinä voimme ajatella vaikkapa Luojat -sarakkeen tämän luvun esimerkeissä. Kyseessä voisi olla tilanne, että emme saisi lisättyä uutta Tv-sarjaa ellemme tiedä myös sen luojaa, mikäli se on pakollinen tieto. Voisimme aina laittaa kyseisen kentän tyhjäksi mutta se usein viittaa tämän kaltaiseen tilanteeseen, jossa riippuvuudet eivät ole määritetty oikein.
Tiedon päivittämisen yhteydessä - Sama informaatio voidaan esittää usealla rivillä. Tällöin tiedon päivittäminen yhden rivin kohdalla voi johtaa tilanteeseen, missä tiedon eheys on laiminlyöty. Voidaan siis joutua tilanteeseen, missä esimerkiksi jokin tunniste ei vastaa sitä vastaavaa aihetta.
Tiedon poistamisen yhteydessä - Poistaessa tietoja saatamme joutua tilanteeseen, jossa poistamalla esimerkiksi TV-sarjat, joudumme poistamaan paljon muita siihen viittaavia tietoja. Tällöin jokin tieto ei voi esiintyä ilman toista vaikka ne oikeassa maailmassa olisivat riippumattomia toisistaan.
Hyvin normalisoidut tietokannan kohdalla tietojen päivittäminen ja sen käyttö on sujuvaa. Uusien tietojen esittäminen ei vaadi rakenteen muuttamista. Kaikki tämä on siis hyvä tavoite ja kun puutteita näkee, niitä pitäisi yrittää korjata ajoissa mallintamalla tietoa uudelleen. Myöhemmässä vaiheessa tämä on usein hankalaa kun tietoa on jo olemassa ja tällöin vaatisi erilaisia migraatioita tietokannan rakenteeseen.
Esimerkin tietokanta jäi 3. normaalimuodon esimerkin kuvauksen muotoiseksi. Tämä ei tarkoita, että tietokanta olisi vielä 3. normaalimuodon mukainen tai edes televisiosarjat -taulu. Edellisiä vaiheita tulisi toistaa loppujen sarakkeiden kohdalla ja ensin koko taulu yrittää saada 1. normaalimuodon mukaiseksi. Tämä tarkoittaisi, että kaikki sarakkeet, joissa on mainittu listana henkilöitä tulisi laittaa omaan tauluunsa.
Huomaamme kuitenkin, että tiedoissa on paljon näyttelijöiden tai muiden henkilöiden nimiä. Tämä toimii vielä hyvänä esimerkkinä, että myös jo luodut taulut eivät välttämättä noudata normaalimuotoja. Tällöin myös ne tulisi tarkastella sääntöjen mukaan ja tarvittaessa pilkkoa tiedon perusteella omiksi kokonaisuuksiksi.
Otetaan vielä lopuksi tilanne, joka vie kohti normaalimuotoja henkilöiden kohdalla. Tehdään seuraavanlainen rakenne tietokantaan.
Esimerkin ero edelliseen on, että henkilöt on lisätty omaan tauluunsa. Henkilöt voivat toimia eri rooleissa kuten pääosassa ja vastaavina. Näille on luotu omat liitostaulunsa ja edetessä luojat -taulu voitaisiin muuttaa samanlaiseksi liitostauluksi. Tällä hetkellä tietoa olisi kopiona ja toistuvana kyseisessä taulussa.
Tällä tavoin myös eri henkilöiden tieto voidaan saada päivitettyä sujuvammin. Tietokannan rakenne tosin taas muuttuu hieman monimuotoisemmaksi, jos jokaiselle eri tehtävälle teemme liitostaulun. Riippuen juuri tilanteesta, väärää vastausta ei ole. Voimme myös ensin yhden esimerkin kautta löytää paremman ratkaisun.
Mikäli vielä kävisimme tietoja läpi niin esimerkin tapauksessa voisi olal myös esimerkiksi televisiosarja_tehtava ja tehtavat taulut. Tällöin voitaisiin päästä rakenteeseen, jossa liitostaulu sisältäisi seuraavat tunnisteet: tv-sarja, henkilo ja tehtävä. Tehtävä -taulussa puolestaan olisi lueteltu erilaisia tehtäviä missä henkilö on voinut toimia kuten vastaavana tuottajana, pääosan esittäjänä jne. Tällainen rakenne voisi siis yhtä hyvin toimia, koska silloin jokainen henkilö voidaan asettaa useampaan eri tehtävään mutta heidän omat tietonsa ei toistu. Myös liitosten määrä vähenee taulujen välillä, joka tarkoittaa yksinkertaisempia kyselyjä.