Kapittel 4 · 4C · Forelesning 9 · Lærebok 7.1–7.3, 7.6

Normalformer

Funksjonelle avhengigheter, lukning, dekomponering, og veien fra 1NF til BCNF — med en interaktiv kalkulator og et helt gjennomarbeidet eksempel.

01 · Funksjonelle avhengigheter

Hvis du vet X, vet du Y

En funksjonell avhengighet (FD) er det formelle språket for hvordan attributter «bestemmer» hverandre. Vi skriver X → Y, og leser det «X bestemmer Y» — eller mer presist: hvis to rader er enige om alle attributter i X, så må de også være enige om alle attributter i Y.

Definisjon
Funksjonell avhengighet

Gitt et relasjonsskjema R, og delmengder X, Y ⊆ R. FD-en X → Y holder på R hvis enhver lovlig instans r(R) tilfredsstiller: for hvert par av tupler t₁, t₂ i r, hvis t₁[X] = t₂[X], så er t₁[Y] = t₂[Y].

Hva FD-er er og ikke er

  • FD-en er en regel om alle gyldige instanser, ikke et empirisk faktum om en konkret tabell.
  • Det at en konkret instans tilfeldigvis tilfredsstiller en FD, betyr ikke at FD-en holder på skjemaet.
  • FD-er kommer fra domenekunnskap: «hver bil har én eier», «hvert rom har én kapasitet i en gitt bygning».
En instans av r(A,B,C,D)
ABCD
a₁b₁c₁d₁
a₁b₂c₁d₂
a₂b₂c₂d₂
a₂b₃c₂d₃
a₃b₃c₂d₄

I instansen ovenfor: A → C er tilfredsstilt (begge a₁-rader har c₁; begge a₂-rader har c₂). Derimot er C → A ikke tilfredsstilt: rad 4 og 5 har samme C (c₂) men ulik A (a₂ vs a₃).

Trivielle FD-er

En FD X → Y er triviell hvis Y ⊆ X — den holder for alle instanser uansett. {A, B} → A er triviell. Vi bryr oss bare om ikke-trivielle FD-er.

Sjekk · MCQ
Hvilken FD holder på skjemaet Klasserom(bygning, romnr, kapasitet)?
Bygning + romnr er primærnøkkel, så det bestemmer alt annet i raden. romnr → kapasitet alene er ikke gyldig — to bygninger kan ha rom med samme nummer, men ulik kapasitet.
02 · Armstrongs aksiomer

Tre regler som genererer alle

Gitt en mengde FD-er F, finnes det andre FD-er som holde som logisk konsekvens. Mengden av alle slike kalles lukningen F⁺. Tre aksiomer er nok til å utlede alle:

Refleksivitet
Hvis Y ⊆ X, så X → Y. Triviell.
Augmentasjon
Hvis X → Y, så X, Z → Y, Z for ethvert Z.
Transitivitet
Hvis X → Y og Y → Z, så X → Z.

Disse aksiomene er sunne (de utleder bare gyldige FD-er) og komplette (alt som er logisk gyldig kan utledes). Tre nyttige avledede regler:

  • Union: hvis X → Y og X → Z, så X → Y, Z.
  • Dekomposisjon: hvis X → Y, Z, så X → Y og X → Z.
  • Pseudotransitivitet: hvis X → Y og W, Y → Z, så W, X → Z.
03 · Lukning & kalkulator

Hva kan vi utlede?

Definisjon
Attributtlukning X⁺

Settet av alle attributter som er funksjonelt bestemt av X under en gitt FD-mengde F. Skrives X⁺ (eller X⁺F).

Algoritmen

  1. Initialiser resultat ← X.
  2. For hver FD α → β i F: hvis α ⊆ resultat, oppdater resultat ← resultat ∪ β.
  3. Gjenta steg 2 til resultat ikke endrer seg.

Hva bruker vi X⁺ til?

  • Supernøkkel-test: X er supernøkkel hvis og bare hvis X⁺ = R.
  • FD-test: X → Y følger fra F hvis og bare hvis Y ⊆ X⁺.
  • Lossless join-test: for binær dekomposisjon R₁, R₂, sjekk om (R₁ ∩ R₂)⁺ ⊇ R₁ eller R₂.

Interaktiv lukningskalkulator

Et lite leksjonseksempel: R(A, B, C, D, E) med F = { A → B, B → C, CD → E, E → A }. Velg attributter for X, og se lukningen utvikle seg trinn for trinn.

F = { A → B,   B → C,   CD → E,   E → A }
Velg X:
Prøv selv

Hva er {A}⁺? Hva med {D}⁺? Hva med {A, D}⁺? Når du finner et X der X⁺ = {A,B,C,D,E}, har du funnet en supernøkkel.

Sjekk · Middels
Bruk kalkulatoren ovenfor til å avgjøre: er {C, D} en supernøkkel?
Ja. {C,D}⁺ via CD→E gir {C,D,E}; så E→A gir {A,C,D,E}; så A→B gir {A,B,C,D,E}. Dekker hele R, altså supernøkkel. Den er også minimal — verken {C} eller {D} alene gir hele R — så {C,D} er en kandidatnøkkel.
04 · Nøkler fra FD-er

Finn alle kandidatnøkler

Tre nøkkelbegreper, formelt

Supernøkkel for R: et sett K der K⁺ = R. Kandidatnøkkel: en supernøkkel som er minimal (ingen ekte delmengde er supernøkkel). Primærnøkkel: en valgt kandidatnøkkel.

Algoritme: alle kandidatnøkler

  1. Identifiser hvilke attributter aldri er på høyre side i en FD (eller bare i en FD som også har dem på venstre side). De må være med i hver kandidatnøkkel.
  2. Identifiser hvilke attributter aldri er på venstre side. De er ikke nødvendige.
  3. For de mellomliggende attributtene: prøv minimale supersett av (1) og se om lukningen dekker R.

I R(A,B,C,D,E) med F fra forrige seksjon: D dukker aldri opp på høyre side, så D må være med i hver kandidatnøkkel. {A,B,C,E} er gjensidig avledbare via FD-syklusen A→B→C→A (gjennom CD→E→A). Så kandidatnøklene er {A,D}, {B,D}, {C,D}, {E,D}.

Sjekk · Vanskelig
For R(A,B,C,D) med F = {AB → C, C → D}, hvilken er kandidatnøkkelen?
{A,B}⁺ = {A,B,C,D} via AB→C, så C→D. {A,B,C} er supernøkkel men ikke minimal — C kan fjernes. {A} alene gir bare {A}; {C} bare {C, D}.
05 · Dekomponering

Splitt en relasjon — uten å miste informasjon

Når vi splitter R i to skjemaer R₁ og R₂, vil vi at den naturlige join-en av r₁ og r₂ reproduserer den opprinnelige r nøyaktig. Hvis det er tilfellet, er dekomposisjonen lossless.

Tap er ikke alltid synlig

En lossy dekomposisjon kan gi flere rader etter join — men noen av dem er falske. Ekstra «tupler» som ikke svarer til virkeligheten er nettopp tap av informasjon: vi har mistet evnen til å skille hvilke rader som hører sammen.

Lossless join-testen

For binær dekomposisjon av R i R₁ og R₂, hvor minst én av disse FD-ene gjelder i F⁺:

  • R₁ ∩ R₂ → R₁, eller
  • R₁ ∩ R₂ → R₂.

Med andre ord: skjæringen må være supernøkkel for minst én av delene.

Eksempel: lossy

R(ID, navn, gate, by, lønn). Vi splitter på navn:

  • R₁(ID, navn)
  • R₂(navn, gate, by, lønn)

Skjæringen er {navn}. Men «navn» er ikke unikt — to ulike personer kan hete «Kim Hansen». {navn}⁺ = {navn} (ingen FD med navn på venstre side, alene). Ikke supernøkkel for noen av delene → lossy. Etter join får vi krysskobling mellom de to Kim-radene, og kan ikke lenger fortelle hvilken adresse som hører til hvilken Kim.

Eksempel: lossless

R(ID, navn, dept, bygning, budsjett). Vi splitter på dept:

  • R₁(ID, navn, dept)
  • R₂(dept, bygning, budsjett)

Skjæringen er {dept}. Vi vet at dept → bygning, budsjett, så {dept}⁺ ⊇ R₂. Supernøkkel for R₂ → lossless.

Dependency preservation

Definisjon
Avhengighetsbevarende dekomposisjon

Dekomposisjonen er dependency preserving hvis foreningen av FD-ene som kan testes lokalt i hver del, fortsatt er logisk ekvivalent med F. Hvis ikke, må noen FD-er sjekkes med en join etter hver oppdatering — kostbart.

Lossless og dependency preserving er uavhengige egenskaper. Ideelt sett vil vi ha begge. Vi kan alltid få lossless. Vi kan ikke alltid få begge samtidig med BCNF — men 3NF garanterer det.

06 · Normalformer-stigen

Fra 1NF til BCNF

1NF
Atomære verdier i hver celle. Ingen lister, ingen sammensatte verdier. Dette er en betingelse på domener, ikke på FD-er. Bryter du 1NF, kan du ikke spørre med vanlig SQL.
2NF
Ingen partielle avhengigheter til primærnøkkelen. Et ikke-nøkkel-attributt avhenger av hele nøkkelen, ikke bare en del av den. Bare relevant når PK er sammensatt. Av historisk interesse — moderne kurs hopper rett til 3NF/BCNF.
3NF
Ingen transitive avhengigheter til primærnøkkelen. For hver ikke-triviell FD α → β: enten er α supernøkkel, eller hvert attributt i β−α er del av en kandidatnøkkel. Garantert lossless + dependency preserving dekomposisjon.
BCNF
Hver ikke-triviell FD har supernøkkel som venstreside. Strengere enn 3NF. Eliminerer all redundans som kan oppdages med FD-er — men kan tape dependency preservation.
Hierarkiet

BCNF ⊂ 3NF ⊂ 2NF ⊂ 1NF. Et BCNF-skjema er automatisk i 3NF, og videre i 2NF og 1NF.

3NF i ord

For hver ikke-triviell FD α → β som holder, må minst én av:

  • α er supernøkkel for R, eller
  • hvert attributt i β − α er med i en eller annen kandidatnøkkel for R.

BCNF i ord

For hver ikke-triviell FD α → β som holder, må:

  • α er supernøkkel for R.

Det er det. BCNF har bare ett alternativ — det andre alternativet i 3NF er det som åpner for dependency preservation, men også for visse redundanser.

07 · BCNF

Boyce–Codd normalform

Algoritme: dekomposer R til BCNF

  1. Beregn alle FD-er som holder (lukningen F⁺).
  2. Finn en ikke-triviell FD α → β hvor α ikke er supernøkkel. Hvis ingen finnes, er R i BCNF — ferdig.
  3. Splitt R i R₁ = α ∪ β og R₂ = R − (β − α).
  4. Gjenta rekursivt på R₁ og R₂.

Eksempel

InDep(id, navn, lønn, dept, bygning, budsjett) med F = {id → navn, lønn, dept; dept → bygning, budsjett}.

  • FD-en dept → bygning, budsjett bryter BCNF: dept er ikke supernøkkel.
  • Splitt: α = dept, β = {bygning, budsjett}.
  • R₁ = (dept, bygning, budsjett) → kalt Avdeling.
  • R₂ = R − (β − α) = (id, navn, lønn, dept) → kalt Larer.

Verifiser: id → navn, lønn, dept har id som supernøkkel. dept → bygning, budsjett har dept som supernøkkel i R₁. Begge tabeller er nå i BCNF.

Sjekk lossless

Skjæringen R₁ ∩ R₂ = {dept}. {dept}⁺ inkluderer {bygning, budsjett}, altså hele R₁ — supernøkkel. Lossless. ✓

08 · Gjennomarbeidet eksempel

Helt fra tabell til BCNF

Gitt skjemaet R(prosjektkode, prosjektnavn, ansattnr, navn, timer) der vi registrerer hvor mange timer hver ansatt har jobbet på hvert prosjekt. Krav fra domenet:

  • Hvert prosjekt har et unikt navn: prosjektkode → prosjektnavn.
  • Hver ansatt har et navn (ikke unikt mellom personer): ansattnr → navn.
  • For hver (ansatt, prosjekt) registreres timer: ansattnr, prosjektkode → timer.

Steg 1 · Finn kandidatnøkkel

Hvilke attributter er aldri på høyre side? ansattnr og prosjektkode. De må være med. {ansattnr, prosjektkode}⁺ = {ansattnr, prosjektkode, navn, prosjektnavn, timer} = R. Minimal supernøkkel → kandidatnøkkel.

Steg 2 · Sjekk BCNF

FD-er å sjekke:

  1. prosjektkode → prosjektnavn — er {prosjektkode} supernøkkel? {prosjektkode}⁺ = {prosjektkode, prosjektnavn}. Ikke hele R. Bryter BCNF.
  2. ansattnr → navn — er {ansattnr} supernøkkel? {ansattnr}⁺ = {ansattnr, navn}. Ikke hele R. Bryter BCNF.
  3. ansattnr, prosjektkode → timer — er {ansattnr, prosjektkode} supernøkkel? Ja (det er kandidatnøkkelen). OK.

Steg 3 · Dekomponer

Velg første brudd: prosjektkode → prosjektnavn. Splitt:

  • R₁ = {prosjektkode, prosjektnavn} → Prosjekt
  • R₂ = R − {prosjektnavn} = {prosjektkode, ansattnr, navn, timer}

R₁ er i BCNF (skjema med to attributter er alltid i BCNF — et nyttig faktum). R₂ må sjekkes videre.

I R₂: ansattnr → navn bryter fortsatt. Splitt:

  • R₂ₐ = {ansattnr, navn} → Ansatt
  • R₂ᵦ = R₂ − {navn} = {prosjektkode, ansattnr, timer} → Jobber

Begge er nå i BCNF.

Sluttskjema

CREATE TABLE Prosjekt (
  prosjektkode    CHAR(6) PRIMARY KEY,
  prosjektnavn    VARCHAR(100) UNIQUE NOT NULL
);

CREATE TABLE Ansatt (
  ansattnr  INT PRIMARY KEY,
  navn      VARCHAR(80) NOT NULL
);

CREATE TABLE Jobber (
  ansattnr      INT,
  prosjektkode  CHAR(6),
  timer         DECIMAL(5,1) NOT NULL,
  PRIMARY KEY (ansattnr, prosjektkode),
  FOREIGN KEY (ansattnr) REFERENCES Ansatt(ansattnr),
  FOREIGN KEY (prosjektkode) REFERENCES Prosjekt(prosjektkode)
);
Resultat

Tre tabeller, hver i BCNF. Ingen redundans (prosjektnavn lagres én gang per prosjekt; ansattnavn lagres én gang per ansatt). Lossless: skjæringene er supernøkler. Dependency preserving: alle tre FD-er kan sjekkes lokalt.

Sjekk · Vanskelig
Sjekk lossless: ved den første splittingen var R₁ ∩ R₂ = {prosjektkode}. Hva er {prosjektkode}⁺ på det punktet? Holder lossless join-testen?
{prosjektkode}⁺ = {prosjektkode, prosjektnavn}, som er hele R₁. Skjæringen er supernøkkel for R₁ → lossless join holder. ✓ Det samme prinsippet ved splittingen R₂ → R₂ₐ + R₂ᵦ: skjæringen {ansattnr} dekker R₂ₐ.
09 · 3NF vs. BCNF

Når BCNF koster for mye

Det klassiske eksempelet: dept_advisor(student, lærer, dept) der:

  • en lærer er knyttet til nøyaktig ett institutt: lærer → dept
  • en student kan ha flere veiledere, men maks én per institutt: student, dept → lærer

Kandidatnøkler: {student, dept} og {student, lærer}. FD-en lærer → dept bryter BCNF (lærer er ikke supernøkkel). Splitt:

  • R₁ = (lærer, dept)
  • R₂ = (student, lærer)

Begge er i BCNF. Men: FD-en student, dept → lærer kan ikke lenger sjekkes lokalt — student er i R₂, dept er i R₁. Hver gang noen legger til en (student, lærer)-par, må vi joine for å verifisere constrainten.

Velg BCNF når

  • SQL likevel ikke kan håndheve generelle FD-er effektivt (det meste av tiden)
  • Du foretrekker å eliminere all FD-redundans
  • Lærebokas anbefaling — standardvalget

Velg 3NF når

  • Du har en tapt FD som er forretningskritisk og som sjekkes per oppdatering
  • Du har infrastruktur for materialiserte views med constraints
  • Eksamensoppgaven eksplisitt ber om dependency preservation
Lærebokas konklusjon

«Selv om vi ikke alltid kan få en dependency-preserving BCNF-dekomposisjon, er det fortsatt foretrukket å gå for BCNF — fordi sjekking av andre FD-er enn primærnøkkelen er vanskelig i SQL likevel.» (Silberschatz §7.3.3)

Oppsummering av kapittel 4

FD X→Y: hvis du vet X, vet du Y
Lukning X⁺ alle attributter X bestemmer
Supernøkkel X⁺ = R
Kandidatnøkkel minimal supernøkkel
Lossless skjæring er supernøkkel for én del
Dep. preservation alle FD-er sjekkbare lokalt
1NF atomære verdier
3NF α supernøkkel, eller β−α i kandidatnøkkel
BCNF α supernøkkel — alltid
BCNF-algoritme finn brudd, splitt på α∪β og R−(β−α)
Du er ferdig med kapittel 4

Vil du teste hele kapittelet samlet? Gå tilbake til oversikten og ta sluttquizen — tolv spørsmål på tvers av 4A, 4B og 4C.