1/60Normalizacja baz danych – 4NF: Czwarta postać normalna

Eliminacja zależności wielowartościowych – gdy BCNF to za mało

Zakładamy znajomość 1NF, 2NF, 3NF i BCNF.

Prezentacja kontynuuje przykład systemu bibliotecznego z poprzednich prezentacji (BD_1NF, BD_2NF, BD_3NF, BCNF).

4NF została zdefiniowana przez Ronalda Fagina w 1977 roku – to krok poza zależności funkcyjne, w świat zależności wielowartościowych
Slajd tytułowy – 4NF jako kolejny krok normalizacji po BCNF

4NF (czwarta postać normalna) została wprowadzona przez Ronalda Fagina w 1977 roku jako naturalne rozszerzenie BCNF. O ile BCNF eliminuje wszystkie anomalie związane z zależnościami funkcyjnymi (FD), o tyle nie radzi sobie z szerszą klasą zależności – zależnościami wielowartościowymi (MVD). Typowym przykładem jest sytuacja, w której jeden czytelnik biblioteczny ma wiele numerów telefonów i wiele adresów e-mail. Są to dwie niezależne listy: liczba telefonów nie ma związku z liczbą emaili.

W BCNF taka tabela byłaby formalnie poprawna, ponieważ nie ma w niej nielegalnych FD, ale w praktyce generuje ogromną redundancję – produkt kartezjański między listami. Dla czytelnika z 3 telefonami i 4 emailami otrzymujemy 12 wierszy zamiast 7. 4NF rozwiązuje ten problem, wymagając aby każda MVD wynikała z klucza głównego. Jeśli tak nie jest – dzielimy tabelę na osobne tabele dla każdej niezależnej listy.

W bibliotece oznacza to, że dane kontaktowe czytelnika powinny być przechowywane w trzech tabelach: Czytelnicy (dane stałe), Telefony i Emaile. Każda z tych tabel przechowuje jeden niezależny fakt, co eliminuje produkt kartezjański i wynikające z niego anomalie.

2/60Agenda prezentacji – plan podróży przez 60 slajdów

Sześć części – od powtórki po podsumowanie

Prezentacja składa się z sześciu części:

  • Część 0: Powtórka – od 1NF do BCNF (slajdy 1-8)
  • Część I: Co to są zależności wielowartościowe? (slajdy 9-18)
  • Część II: Definicja 4NF – reguły i przykłady (slajdy 19-28)
  • Część III: Przykład z biblioteką – dane kontaktowe (slajdy 29-40)
  • Część IV: Implementacja w MariaDB (slajdy 41-52)
  • Część V: Podsumowanie i zapowiedź 5NF (slajdy 53-60)
BCNF radzi sobie ze wszystkimi zależnościami funkcyjnymi. Ale są też inne typy zależności – MVD. 4NF je eliminuje.
Mapa prezentacji – sześć części od powtórki przez MVD, 4NF, implementację po podsumowanie

Prezentacja została podzielona na sześć logicznych części, które prowadzą słuchacza od przypomnienia wcześniejszych postaci normalnych przez wprowadzenie nowego typu zależności (MVD), aż po praktyczną implementację w MariaDB. Taka struktura pozwala stopniowo budować zrozumienie: najpierw utrwalamy wiedzę o BCNF i jej ograniczeniach, potem poznajemy narzędzie (MVD), które opisuje te ograniczenia, a następnie uczymy się, jak 4NF je eliminuje.

Najważniejsza w tej agendzie jest część I (definicja MVD) i część II (definicja 4NF), ponieważ stanowią one teoretyczny fundament. Część III pokazuje praktyczne zastosowanie na przykładzie systemu bibliotecznego, a część IV demonstruje, jak przełożyć teorię na kod SQL. Dwie ostatnie części (V i VI) podsumowują cykl i przygotowują grunt pod 5NF.

Studenci powinni zwrócić szczególną uwagę na różnicę między FD a MVD – to klucz do zrozumienia, dlaczego BCNF nie wystarcza i dlaczego potrzebujemy 4NF. Bez tego rozróżnienia dalsze slajdy będą trudne do przyswojenia.

3/60Powtórka: gdzie jesteśmy po BCNF?

BCNF – sukces w eliminacji FD, ale nie wszystkich problemów

Po 3NF/BCNF: każda zależność funkcyjna X → A ma X jako nadklucz.

  • Zależności funkcyjne – w pełni wyeliminowane
  • Wciąż możliwe problemy: niezależne atrybuty wielowartościowe
  • BCNF eliminuje anomalie związane z FD, ale nie z MVD
BCNF świetnie radzi sobie z zależnościami funkcyjnymi – ale są też inne typy zależności. BCNF ich nie dotyczy.
Schemat BCNF – wszystkie FD wyeliminowane, ale pozostają MVD jako osobny problem

BCNF (Boyce-Codd Normal Form) jest często uznawana za ostateczną wersję 3NF. Gwarantuje, że każda zależność funkcyjna (FD) w tabeli ma swój wyznacznik będący nadkluczem. W praktyce oznacza to, że nie ma w tabeli "ukrytych" zależności, które mogłyby prowadzić do anomalii przy aktualizacji danych. Biblioteczna baza po BCNF składa się z 6 tabel, które przechowują informacje o czytelnikach, książkach, miastach, wypożyczeniach, opiekunach i przypisaniach.

Jednak BCNF bada tylko zależności funkcyjne, czyli takie, gdzie jedna wartość jednoznacznie wyznacza drugą (np. ID_Czytelnika → Nazwisko). Nie bada ona sytuacji, w której jedna wartość wyznacza cały zbiór niezależnych wartości, czyli zależności wielowartościowych (MVD). Dlatego tabela w BCNF może wciąż zawierać problematyczne dane, o ile problem nie leży w FD, ale w MVD.

To tak, jakbyśmy sprawdzili, czy wszystkie drzwi w domu są zamknięte (BCNF), ale zapomnieli sprawdzić, czy okna też są zamknięte (MVD). Gość może wejść przez okno, nawet jeśli drzwi są zamknięte. 4NF "zamyka okna", czyli eliminuje problemy związane z MVD.

4/60Powtórka: co to jest zależność funkcyjna (FD)?

FD – fundament normalizacji

  • FD: X → Y – znając X, znamy dokładnie Y
  • Przykład: ID_Czytelnika → Nazwisko (jeden czytelnik = jedno nazwisko)
  • FD daje JEDNĄ wartość dla danego X
  • FD to 'mapowanie 1:1' między wartościami
FD to pewność: znasz ID, znasz dokładnie nazwisko. Jedno ID = jedna wartość. Zero niepewności.
Ilustracja FD – strzałka od ID_Czytelnika do Nazwisko, jeden ID = jedno nazwisko

Zależność funkcyjna (FD) to podstawowe pojęcie w teorii normalizacji. Mówimy, że X → Y (X funkcyjnie wyznacza Y), jeśli każda wartość X jest związana z dokładnie jedną wartością Y. W przykładzie bibliotecznym: ID_Czytelnika → Nazwisko oznacza, że każdy czytelnik ma dokładnie jedno nazwisko przypisane do swojego identyfikatora. Nie ma możliwości, aby ten sam ID_Czytelnika wskazywał na dwa różne nazwiska.

FD jest fundamentalna, ponieważ pozwala wykrywać redundancję: jeśli w tabeli wielokrotnie powtarza się ta sama para (ID_Czytelnika, Nazwisko), oznacza to, że dane są zduplikowane i mogą prowadzić do anomalii. Gdybyśmy zmienili nazwisko w jednym wierszu, a zapomnieli w innym, dane stałyby się niespójne. Normalizacja (2NF, 3NF, BCNF) eliminuje te problemy, rozdzielając dane na osobne tabele.

W kontekście 4NF FD jest punktem wyjścia, ale nie wystarcza. BCNF zapewnia, że wszystkie FD są "legalne", ale nie gwarantuje, że nie ma innych typów zależności (MVD). To jak sprawdzenie, że każde dziecko ma dokładnie jednego rodzica (FD), ale nie sprawdzenie, że rodzic może mieć wiele dzieci (MVD).

5/60Powtórka: tabela po BCNF – przykład z biblioteką

Obecny schemat biblioteki – 6 tabel w BCNF

Obecny schemat biblioteki:

  • Czytelnicy (ID_Czytelnika, Imie, Nazwisko, ID_Miasta)
  • Miasta (ID_Miasta, Nazwa, KodPocztowy)
  • Ksiazki (ISBN, Tytul, ID_Gatunku, RokWydania)
  • Wypozyczenia (ID_Wyp, ID_Czytelnika, ISBN, DataWyp, DataZwrotu)
  • Opiekunowie (ID_Czytelnika, ID_Bibliotekarza)
  • Przypisania_BCNF (ID_Czytelnika, ISBN, DataPrzypisania)

Wszystkie tabele w BCNF – żadnych problemów z FD.

Nasza baza biblioteczna po BCNF – 6 tabel, każda w BCNF. Wszystkie FD są 'legalne'. Ale czy to koniec problemów?
Schemat 6 tabel biblioteki po BCNF z relacjami między nimi

Po przejściu przez 1NF, 2NF, 3NF i BCNF nasza baza biblioteczna ma 6 tabel: Czytelnicy, Miasta, Ksiazki, Wypozyczenia, Opiekunowie i Przypisania_BCNF. Każda z tych tabel spełnia rygorystyczne wymagania BCNF, co oznacza, że żadna zależność funkcyjna nie powoduje już anomalii. Klucze główne są prawidłowo zdefiniowane, a dane są przechowywane bez zbędnej redundancji wynikającej z FD.

W tabeli Czytelnicy mamy dane osobowe czytelników, Miasta stanowią słownik miast z kodami pocztowymi, Ksiazki zawierają informacje o książkach, a Wypozyczenia łączą czytelników z książkami. Opiekunowie realizują relację wiele-do-wielu między czytelnikami a bibliotekarzami, a Przypisania_BCNF przechowują dodatkowe informacje o przypisaniach. Każda z tych tabel ma prostą strukturę z jasno określonymi zależnościami.

Mimo to, jak za chwilę zobaczymy, istnieją jeszcze problemy, których BCNF nie wychwytuje. Dotyczą one sytuacji, w których w jednej tabeli przechowujemy dwie niezależne listy wartości dla tego samego obiektu. W naszej bibliotece przykładem są dane kontaktowe: czytelnik może mieć wiele telefonów i wiele emaili, a te listy są od siebie niezależne.

6/60Powtórka: czego BCNF nie eliminuje?

BCNF dotyczy tylko FD – są inne typy zależności

BCNF dotyczy TYLKO zależności funkcyjnych (FD).

FD = gdy jedna wartość wyznacza drugą wartość.

Istnieją inne typy zależności:

  • Zależności wielowartościowe (MVD) – jedna wartość wyznacza ZBIÓR wartości
  • Zależności złączeniowe (JD) – relacje między całymi grupami kolumn

4NF eliminuje MVD, 5NF eliminuje JD.

BCNF zamyka rozdział FD. Ale otwiera się nowy: MVD – gdy jedna wartość prowadzi do WIELU niezależnych wartości.
Trzy typy zależności: FD (strzałka), MVD (strzałka do zbioru), JD (diagram złączenia)

BCNF eliminuje wszystkie problemy wynikające z zależności funkcyjnych (FD). Jeśli w tabeli istnieje FD X → Y, to w BCNF X musi być nadkluczem. To gwarantuje, że żadna wartość nie jest niepotrzebnie powielana z powodu zależności funkcyjnych. Jednak istnieją dwa inne typy zależności, którymi BCNF się nie zajmuje: zależności wielowartościowe (MVD) i zależności złączeniowe (JD).

MVD różni się od FD fundamentalnie: podczas gdy FD mówi "znasz X, znasz dokładnie jeden Y", MVD mówi "znasz X, znasz zbiór możliwych Y". Na przykład ID_Czytelnika →→ Telefon oznacza, że czytelnik może mieć wiele telefonów, ale nie ma FD, która by wyznaczała konkretny telefon. To "wiele" jest kluczowe – FD daje pewność, MVD daje zbiór możliwości.

4NF eliminuje MVD, a 5NF eliminuje JD. W tej prezentacji skupiamy się na MVD i 4NF. Warto zapamiętać hierarchię: FD ⊂ MVD ⊂ JD, czyli każda FD jest szczególnym przypadkiem MVD (gdy zbiór ma jeden element), a każda MVD jest szczególnym przypadkiem JD (dla dwóch zbiorów). Kolejne postaci normalne eliminują coraz ogólniejsze typy zależności.

7/60Powtórka: co to są zależności wielowartościowe (MVD)?

MVD – gdy jedna wartość wyznacza zbiór wartości

MVD: A →→ B (A wielowyznacza B)

  • Dla danej wartości A, istnieje ZBIÓR wartości B
  • B jest niezależne od pozostałych atrybutów

Różnica FD vs MVD:

  • FD: ID_Czyt → Nazwisko – JEDNO nazwisko
  • MVD: ID_Czyt →→ Telefon – WIELE telefonów
FD to 'znasz X, znasz dokładnie Y'. MVD to 'znasz X, znasz LISTĘ możliwych Y'. To fundamentalna różnica.
Porównanie FD (jedna wartość) vs MVD (zbiór wartości) na przykładzie ID_Czytelnika

Zależność wielowartościowa (MVD) oznaczana jest symbolem A →→ B i czytana jako "A wielowyznacza B". Oznacza to, że dla danej wartości A istnieje zbiór wartości B, które mogą być z nią powiązane. W przeciwieństwie do FD, gdzie dla danego A mamy dokładnie jedną wartość B, w MVD dla danego A możemy mieć wiele wartości B, a wszystkie są równie poprawne.

Przykład z biblioteki: ID_Czytelnika →→ Telefon. Dla czytelnika o ID=1 możemy mieć telefony '123-456-789', '987-654-321' i '555-111-222'. Każdy z tych telefonów jest poprawny dla tego czytelnika i nie ma między nimi hierarchii. Gdybyśmy mieli FD ID_Czytelnika → Telefon, to czytelnik mógłby mieć tylko jeden telefon – to oczywiście nieprawda w rzeczywistości.

Najważniejsza własność MVD: atrybuty po prawej stronie (B) są niezależne od pozostałych atrybutów w tabeli (C = R – A – B). Oznacza to, że wartości B i C dla danego A mogą wystąpić w dowolnej kombinacji. To właśnie ta niezależność prowadzi do produktu kartezjańskiego, który jest głównym problemem eliminowanym przez 4NF.

8/60Wprowadzenie do problemu: po co 4NF?

BCNF może ukrywać problem – produkt kartezjański

Tabela w BCNF może wciąż zawierać problematyczne dane.

Przykład: DaneKontaktowe (ID_Czytelnika, Telefon, Email)

  • BCNF: jedyna FD to (ID_C, Telefon, Email) → wszystkie – spełnione
  • Ale: ID_Czytelnika →→ Telefon i ID_Czytelnika →→ Email – MVD istnieją
  • Problem: produkt kartezjański między telefonami a emailami
BCNF mówi: 'wszystko OK, nie ma nielegalnych FD'. Ale produkt kartezjański mówi: 'jednak jest problem'. 4NF rozwiązuje ten problem.
Tabela DaneKontaktowe z produktem kartezjańskim – każdy telefon sparowany z każdym emailem

Po co nam 4NF, skoro mamy już BCNF? Odpowiedź jest prosta: BCNF nie eliminuje wszystkich anomalii. Rozważmy tabelę DaneKontaktowe (ID_Czytelnika, Telefon, Email). W BCNF ta tabela jest formalnie poprawna: jedyną FD jest (ID_Czytelnika, Telefon, Email) → (ID_Czytelnika, Telefon, Email), a to jest trywialne. Nie ma żadnych "nielegalnych" FD.

Jednak w praktyce tabela zachowuje się problematycznie. Jeśli czytelnik ma 3 telefony i 4 emaile, w tabeli pojawi się 12 wierszy (3 × 4). To produkt kartezjański między listą telefonów a listą emaili. Każdy telefon jest sparowany z każdym emailem, co jest sztuczne – w rzeczywistości telefony i emaile są niezależne, a nie połączone w pary.

Anomalie są oczywiste: dodanie nowego telefonu wymaga 4 INSERT-ów (dla każdego emaila), zmiana emaila wymaga 3 UPDATE-ów (dla każdego telefonu), a usunięcie telefonu wymaga wielu DELETE-ów. 4NF rozwiązuje ten problem poprzez rozdzielenie niezależnych list na osobne tabele, eliminując produkt kartezjański u źródła.

9/60Definicja zależności wielowartościowej (MVD)

Formalna definicja MVD

Oznaczenie: A →→ B (A wielowyznacza B)

Formalnie: w relacji R, A →→ B jeśli dla każdej pary krotek t1, t2 gdzie t1.A = t2.A:

  • Istnieje krotka t3 gdzie t3.A = t1.A, t3.B = t1.B, t3.C = t2.C (C = R – A – B)
  • I symetrycznie: t4 gdzie t4.A = t1.A, t4.B = t2.B, t4.C = t1.C

Mówiąc prościej: wartości B i C są niezależne dla danej wartości A.

Definicja formalna MVD jest skomplikowana – ale w praktyce: jeśli dwa zbiory wartości są niezależne dla tego samego obiektu, masz MVD.
Diagram formalnej definicji MVD – cztery krotki pokazujące niezależność B i C

Formalna definicja MVD brzmi następująco: w relacji R zachodzi A →→ B, jeśli dla każdych dwóch krotek t1 i t2 takich, że t1.A = t2.A, istnieją krotki t3 i t4 spełniające: t3.A = t4.A = t1.A, t3.B = t1.B, t3.C = t2.C oraz t4.B = t2.B, t4.C = t1.C, gdzie C = R – A – B. Mówiąc prościej: wartości B i C są wymienne dla danej wartości A.

W praktyce definicja ta oznacza, że jeśli mamy dwa wiersze z tą samą wartością A, ale różnymi wartościami B i C, to możemy "wymieszać" wartości B i C między tymi wierszami i nadal otrzymać poprawne wiersze w relacji. To jest właśnie niezależność: B i C nie są ze sobą powiązane, można je dowolnie łączyć.

Na przykładzie bibliotecznym: jeśli mamy wiersze (ID=1, Tel='123', Email='jan@example.com') i (ID=1, Tel='987', Email='jan@work.com'), to MVD ID →→ Tel | Email oznacza, że poprawne są również kombinacje (ID=1, Tel='123', Email='jan@work.com') i (ID=1, Tel='987', Email='jan@example.com'). Jeśli te kombinacje nie są poprawne w rzeczywistości, to MVD nie zachodzi.

10/60MVD – intuicyjne wyjaśnienie

FD vs MVD na przykładzie bibliotecznym

  • FD: ID_Czyt → Miasto – każdy czytelnik ma DOKŁADNIE JEDNO miasto
  • MVD: ID_Czyt →→ Telefon – każdy czytelnik może mieć WIELE telefonów
  • MVD: ID_Czyt →→ Email – każdy czytelnik może mieć WIELE emaili
  • Klucz: telefony i emaile są NIEZALEŻNE – czytelnik może mieć 2 telefony i 3 emaile
  • Nie ma związku między konkretnym telefonem a konkretnym emailem
FD = 'dokładnie jeden'. MVD = 'lista, zbiór, wiele'. FD to igła w stogu siana, MVD to cały stóg.
Wizualizacja: czytelnik z wieloma telefonami i emailami – FD (jeden) vs MVD (wiele)

Intuicyjnie MVD można rozumieć jako "listę zakupów" dla danego obiektu. FD to jak przepis kulinarny: znasz danie (X), znasz dokładnie składnik (Y). MVD to jak lista zakupów: znasz osobę (X), znasz listę rzeczy do kupienia (Y), ale nie wiesz, którą kupi najpierw.

Różnica między FD a MVD jest fundamentalna dla projektowania baz danych. FD to relacja funkcyjna: ID_Czytelnika → Miasto oznacza, że czytelnik mieszka w dokładnie jednym mieście. MVD to relacja wielowartościowa: ID_Czytelnika →→ Telefon oznacza, że czytelnik może mieć wiele telefonów, ale nie ma FD, która by wyznaczała konkretny.

W systemie bibliotecznym MVD pojawiają się wszędzie tam, gdzie jeden obiekt (czytelnik, książka) ma wiele wartości tego samego typu, które są od siebie niezależne. Dlatego właśnie 4NF jest tak ważna: pozwala odróżnić sytuacje, w których "wiele" jest naturalne i niezależne, od tych, w których "wiele" wynika z innej zależności.

11/60MVD ≠ FD – porównanie

Tabela porównawcza FD vs MVD

CechaFDMVD
OznaczenieX → YX →→ Y
Liczba wartości Y dla danego XDokładnie 1Wiele (zbiór)
PrzykładID_Czyt → NazwiskoID_Czyt →→ Telefon
Eliminowana przezBCNF4NF
WystępowanieBardzo częsteRzadsze
Produkt kartezjańskiNie dotyczyTworzy problem
FD i MVD to dwa różne światy. FD to 'jednoznaczność'. MVD to 'niezależność zbiorów'. Łatwo je pomylić – ale różnica jest fundamentalna.
Tabela porównawcza FD vs MVD z kolorowym kodowaniem

Porównanie FD i MVD najlepiej zilustrować na konkretnych przykładach z życia bibliotecznego. FD: ID_Czytelnika → Nazwisko (jeden czytelnik = jedno nazwisko, nie ma wyjątków). MVD: ID_Czytelnika →→ Telefon (jeden czytelnik = wiele telefonów, wszystkie poprawne). FD daje pewność jednoznaczności, MVD dopuszcza zbiór.

Kluczowa różnica leży w liczbie wartości Y dla danego X. Dla FD jest to dokładnie 1 – wartość jest zdeterminowana. Dla MVD jest to wiele – wartości są niezależne i żadna nie jest "bardziej poprawna" od innej. To ma ogromne konsekwencje dla struktury tabeli: FD może wymagać osobnej tabeli (jeśli nie wynika z klucza), MVD zawsze wymaga osobnej tabeli (chyba że jest trywialna).

Warto też pamiętać, że FD jest szczególnym przypadkiem MVD: jeśli A → B (FD), to również A →→ B (MVD), gdzie zbiór wartości B ma dokładnie jeden element. Dlatego BCNF jest szczególnym przypadkiem 4NF: jeśli tabela jest w 4NF, to automatycznie jest w BCNF, ale nie odwrotnie.

12/60Kiedy powstaje MVD?

Typowe sytuacje prowadzące do MVD

Gdy encja ma atrybuty wielokrotne i niezależne.

Typowe przypadki:

  • Osoba ma wiele telefonów i wiele emaili (niezależne listy)
  • Książka ma wielu autorów i wiele kategorii (niezależne listy)
  • Student ma wiele przedmiotów i wiele ról w grupie

Jeśli atrybuty są ZALEŻNE (np. telefon i typ telefonu) – to nie MVD, tylko osobna tabela.

MVD powstaje, gdy DWA (lub więcej) zbiory wartości są niezależne.

MVD = gdy jeden obiekt ma dwie niezależne 'listy zakupów'. Lista telefonów i lista emaili – każda żyje własnym życiem.
Ilustracja: osoba z dwoma listami – telefony i emaile – niezależne od siebie

MVD powstaje, gdy jeden obiekt (encji) ma dwa lub więcej atrybutów, które mogą przyjmować wiele wartości, a te wartości są od siebie niezależne. Typowe przykłady to: osoba z wieloma telefonami i emailami, książka z wieloma autorami i kategoriami, student z wieloma przedmiotami i hobby. We wszystkich tych przypadkach mamy jeden obiekt i dwie (lub więcej) niezależne listy.

Warunkiem koniecznym do powstania MVD jest niezależność list. Jeśli atrybuty są zależne, to nie ma MVD. Na przykład: jeśli książka ma wielu autorów, ale każdy autor jest przypisany do konkretnego rozdziału (a rozdziały są różne), to nie ma MVD między autorem a rozdziałem – są one zależne, bo konkretny autor napisał konkretny rozdział.

W bibliotece typowym przypadkiem MVD są dane kontaktowe czytelników. Każdy czytelnik może mieć wiele telefonów (komórkowy, stacjonarny, służbowy) i wiele emaili (prywatny, służbowy). Liczba telefonów nie ma związku z liczbą emaili – czytelnik może mieć 3 telefony i 2 emaile, 1 telefon i 5 emaili, etc. To właśnie niezależność list generuje MVD.

13/60Problem: dwa niezależne fakty w jednej tabeli

Tabela DaneKontaktowe i produkt kartezjański

Tabela DaneKontaktowe: (ID_Czytelnika, Telefon, Email)

  • Jeden czytelnik może mieć wiele telefonów i wiele emaili
  • Telefon i Email są NIEZALEŻNE – czytelnik może mieć 2 telefony i 3 emaile
  • W BCNF: tabela jest w BCNF (żadnych zależności funkcyjnych poza kluczem)
  • Ale: produkt kartezjański – każdy telefon łączy się z każdym emailem
  • Jeśli czytelnik ma 2 telefony i 3 emaile, w BCNF otrzymasz 6 wierszy
Produkt kartezjański = 2 telefony × 3 emaile = 6 wierszy. Przy 10 telefonach i 20 emailach = 200 wierszy. To nie do utrzymania.
Wizualizacja: 2 telefony × 3 emaile = 6 wierszy w tabeli DaneKontaktowe

Problem dwóch niezależnych faktów w jednej tabeli polega na tym, że przechowujemy w jednym miejscu informacje, które nie są ze sobą bezpośrednio powiązane. Tabela DaneKontaktowe (ID_Czytelnika, Telefon, Email) przechowuje dwa rodzaje faktów: "czytelnik ma numer telefonu" i "czytelnik ma adres email". Te dwa fakty są niezależne, ale tabela wymusza sztuczne połączenie między nimi.

Produkt kartezjański powstaje, gdy dla czytelnika z 2 telefonami i 3 emailami musimy utworzyć 6 wierszy, bo każdy telefon musi być sparowany z każdym emailem. To nie jest rzeczywista zależność między danymi – to artefakt struktury tabeli. W rzeczywistości czytelnik ma po prostu 2 telefony i 3 emaile, a nie 6 "par telefon-email".

Problem narasta wykładniczo z liczbą wartości. Dla czytelnika z 10 telefonami i 20 emailami, w BCNF otrzymamy 200 wierszy. Po normalizacji do 4NF: 10 + 20 = 30 wierszy. Różnica 170 wierszy to nie tylko większe zużycie pamięci, ale przede wszystkim źródło potencjalnych anomalii przy każdej operacji INSERT, UPDATE i DELETE.

14/60Wizualizacja: produkt kartezjański w tabeli

Dane Jana Kowalskiego – 2 telefony × 3 emaile = 6 wierszy

Czytelnik 'Jan Kowalski': 2 telefony, 3 emaile

W tabeli BCNF pojawi się 6 wierszy:

IDTelefonEmail
1123-456-789jan@example.com
1123-456-789jan.kowalski@work.com
1123-456-789j.k@proton.com
1987-654-321jan@example.com
1987-654-321jan.kowalski@work.com
1987-654-321j.k@proton.com
Każdy telefon sparowany z każdym emailem – jak randka w ciemno między telefonami a emailami. Wszystkie kombinacje!
Tabela z 6 wierszami – każdy telefon powtórzony 3 razy, każdy email powtórzony 2 razy

Wizualizacja produktu kartezjańskiego na przykładzie Jana Kowalskiego pokazuje skalę problemu. Jan ma 2 telefony ('123-456-789' i '987-654-321') oraz 3 emaile ('jan@example.com', 'jan.kowalski@work.com', 'j.k@proton.com'). W tabeli naruszającej 4NF pojawia się 6 wierszy, w których każdy telefon jest powtórzony 3 razy (raz dla każdego emaila), a każdy email 2 razy (raz dla każdego telefonu).

Ta redundancja jest nie tylko marnotrawstwem miejsca, ale przede wszystkim źródłem ryzyka. Jeśli Jan zmieni jeden ze swoich emaili, trzeba zaktualizować 2 wiersze (dla każdego telefonu). Jeśli programista zapomni zaktualizować jeden z nich, dane staną się niespójne – część wierszy będzie miała stary email, a część nowy.

Dodatkowo, taka struktura sugeruje, że istnieje związek między konkretnym telefonem a konkretnym emailem (np. '123-456-789' jest "sparowany" z 'jan@example.com'), podczas gdy w rzeczywistości żaden taki związek nie istnieje. To wprowadza w błąd każdego, kto analizuje dane, i może prowadzić do błędnych wniosków biznesowych.

15/60Anomalie w tabeli z MVD

INSERT, UPDATE, DELETE – wszystkie anomalie wracają

  • INSERT: dodanie nowego telefonu wymaga wstawienia wiersza dla KAŻDEGO emaila
    • Nowy telefon = 3 nowe wiersze (bo są 3 emaile)
  • DELETE: usunięcie emaila wymaga usunięcia wielu wierszy
    • Usunięcie emaila = 2 usunięcia (bo są 2 telefony)
  • UPDATE: zmiana numeru telefonu = aktualizacja wielu wierszy
    • Zmiana numeru = UPDATE 3 wierszy (bo są 3 emaile)
  • Problem: wymuszona zależność między niezależnymi faktami
MVD tworzy sztuczną zależność między telefonami i emailami – one są niezależne, a tabela udaje, że są powiązane. Anomalie wracają.
Trzy ikony anomalii: INSERT (dodawanie), UPDATE (modyfikacja), DELETE (usuwanie) z wieloma wierszami

Anomalie w tabeli z MVD to dokładnie te same typy problemów, które znamy z wcześniejszych postaci normalnych: nadmiarowość przy INSERT-ach, ryzyko niespójności przy UPDATE-ach i utrata informacji przy DELETE-ach. Różnica polega na źródle problemu: podczas gdy w 2NF/3NF anomalie wynikały z nieprawidłowych FD, tutaj wynikają z MVD.

INSERT: dodanie nowego telefonu dla czytelnika wymaga wstawienia nowego wiersza dla KAŻDEGO istniejącego emaila. Jeśli czytelnik ma 20 emaili, jeden nowy telefon generuje 20 INSERT-ów. Co gorsza, jeśli chcemy dodać telefon, ale nie znamy jeszcze emaili czytelnika, nie możemy tego zrobić – musielibyśmy wstawić wiersze z NULL-ami lub wymyślonymi wartościami.

DELETE i UPDATE działają symetrycznie: usunięcie emaila wymaga usunięcia wiersza dla każdego telefonu, a zmiana numeru telefonu wymaga aktualizacji wiersza dla każdego emaila. Wszystkie te anomalie znikają po zastosowaniu 4NF, ponieważ każda niezależna lista trafia do osobnej tabeli, gdzie operacje DDL są proste i bezpieczne.

16/60Anomalia INSERT – przykład z biblioteką

Jeden nowy telefon = trzy INSERT-y

Chcemy dodać nowy telefon dla Jana Kowalskiego: '555-123-456'

W tabeli DaneKontaktowe musimy dodać:

  • (1, '555-123-456', 'jan@example.com')
  • (1, '555-123-456', 'jan.kowalski@work.com')
  • (1, '555-123-456', 'j.k@proton.com')

Trzy INSERT-y dla JEDNEGO nowego telefonu!

A jeśli nie znamy jeszcze emaili Jana? Nie możemy dodać samego telefonu.

Jeden nowy telefon = trzy INSERT-y. A gdyby Jan miał 50 emaili? Katastrofa. To anomalia, którą normalizacja miała eliminować.
Ilustracja: jeden telefon w trzech wierszach (dla każdego emaila) – redundancja INSERT

Anomalia INSERT w tabeli naruszającej 4NF jest szczególnie uciążliwa, bo wymaga dodania wielu wierszy dla jednej logicznej operacji. W przykładzie z biblioteką, dodanie nowego telefonu '555-123-456' dla Jana Kowalskiego wymaga trzech INSERT-ów – po jednym dla każdego z jego emaili.

Problem staje się jeszcze bardziej widoczny, gdy czytelnik ma wiele emaili. Jeśli Anna Nowak ma 50 emaili, dodanie dla niej jednego nowego telefonu wymaga 50 INSERT-ów. To nie tylko problem wydajnościowy, ale przede wszystkim ryzyko błędu: jeśli zabraknie jednego INSERT-a, dane będą niespójne.

Co więcej, jeśli chcemy dodać telefon dla nowego czytelnika, który nie ma jeszcze żadnego emaila, nie możemy tego zrobić w tej strukturze. Klucz główny wymaga, aby każdy wiersz miał zarówno telefon, jak i email. Musielibyśmy najpierw dodać "sztuczny" email (np. NULL lub pusty string), co narusza integralność danych. To klasyczny przykład, jak zła struktura tabeli wymusza złe praktyki.

17/60Anomalia DELETE – przykład z biblioteką

Usunięcie jednego emaila = dwa DELETE-y

Chcemy usunąć email 'jan.kowalski@work.com' dla Jana

W tabeli DaneKontaktowe musimy usunąć:

  • (1, '123-456-789', 'jan.kowalski@work.com')
  • (1, '987-654-321', 'jan.kowalski@work.com')

Dwa DELETE-y dla JEDNEGO emaila!

A jeśli usuniemy wszystkie emaile Jana? Stracimy też informację o jego telefonach.

Usunięcie jednego emaila = dwa DELETE-y. Usunięcie wszystkich emaili = utrata informacji o telefonach. Dane są kruche.
Ilustracja: jeden email do usunięcia, ale trzeba usunąć dwa wiersze (dla każdego telefonu)

Anomalia DELETE w tabeli z MVD jest równie poważna. Usunięcie jednego emaila dla czytelnika wymaga usunięcia wszystkich wierszy, w których ten email występuje – czyli po jednym dla każdego telefonu czytelnika. W przykładzie, usunięcie emaila 'jan.kowalski@work.com' dla Jana Kowalskiego wymaga dwóch DELETE-ów (dla telefonu '123-456-789' i '987-654-321').

Jeszcze gorsza sytuacja ma miejsce, gdy chcemy usunąć wszystkie emaile czytelnika (np. czytelnik zrezygnował z korespondencji emailowej). Wtedy tracimy również informację o jego telefonach, bo całe wiersze są usuwane. To nieodwracalna utrata danych – telefonów nie da się odzyskać, bo były przechowywane w tych samych wierszach co emaile.

W 4NF każda lista jest przechowywana osobno, więc usunięcie emaila dotyczy tylko tabeli Emaile – telefony pozostają nienaruszone. To fundamentalna różnica: 4NF izoluje niezależne fakty, chroniąc je przed skutkami operacji na innych, niezależnych faktach.

18/60Anomalia UPDATE – przykład z biblioteką

Zmiana jednego numeru = trzy UPDATE-y

Jan zmienił numer telefonu z '123-456-789' na '111-222-333'

W tabeli DaneKontaktowe musimy zaktualizować:

  • (1, '123-456-789', 'jan@example.com') → (1, '111-222-333', 'jan@example.com')
  • (1, '123-456-789', 'jan.kowalski@work.com') → (1, '111-222-333', 'jan.kowalski@work.com')
  • (1, '123-456-789', 'j.k@proton.com') → (1, '111-222-333', 'j.k@proton.com')

Trzy UPDATE-y dla JEDNEJ zmiany numeru!

Ryzyko błędu: możemy zaktualizować tylko 2 z 3 wierszy – dane stają się niespójne.

Zmiana jednego numeru telefonu = trzy UPDATE-y. A jeśli programista zapomni o jednym? Dane są niespójne. Baza traci wiarygodność.
Ilustracja: trzy wiersze do zaktualizowania – jeden zmieniony, drugi nie – niespójność

Anomalia UPDATE w tabeli z MVD jest być może najgroźniejsza, bo prowadzi do niespójności danych, która może pozostać niezauważona. Zmiana numeru telefonu dla czytelnika wymaga aktualizacji wszystkich wierszy, w których ten numer występuje – czyli po jednym dla każdego emaila. W przykładzie, zmiana numeru z '123-456-789' na '111-222-333' wymaga trzech UPDATE-ów.

Jeśli z jakiegoś powodu tylko dwa z trzech UPDATE-ów się wykonają (np. błąd sieci, przerwanie transakcji), w bazie pozostaną wiersze z oboma numerami: część wierszy będzie miała nowy numer, a część stary. Baza danych będzie zawierać sprzeczne informacje – który numer jest prawdziwy? System nie ma jak tego stwierdzić.

W 4NF zmiana numeru telefonu to jeden UPDATE w tabeli Telefony. Prosty, atomowy, bezpieczny. Nie ma ryzyka pominięcia któregoś wiersza, bo każdy fakt (telefon) występuje dokładnie raz w bazie. To jedna z największych zalet normalizacji: każdy fakt jest przechowywany w jednym miejscu, więc jego aktualizacja jest zawsze prosta i bezpieczna.

19/60Definicja 4NF

4NF = BCNF + warunek na MVD

Relacja jest w 4NF, jeśli:

  1. Jest w BCNF (warunek konieczny)
  2. Dla każdej nietrywialnej zależności wielowartościowej A →→ B:
    • A JEST NADKLUCZEM

Inaczej: żadne dwa niezależne zbiory wartości nie mogą być w tej samej tabeli.

4NF to BCNF + dodatkowy warunek na MVD.

4NF wymaga, aby każda MVD wynikała z klucza głównego – jeśli nie, trzeba rozdzielić na osobne tabele.
Definicja 4NF: BCNF + dla każdej MVD A→→B, A musi być nadkluczem

Definicja 4NF jest zaskakująco prosta: relacja jest w 4NF, jeśli jest w BCNF i każda nietrywialna zależność wielowartościowa (MVD) w tej relacji wynika z klucza głównego (tzn. lewa strona MVD jest nadkluczem). Innymi słowy: 4NF = BCNF + warunek na MVD. To pokazuje, że 4NF jest naturalnym rozszerzeniem BCNF na nowy typ zależności.

Warunek "A jest nadkluczem" oznacza, że jeśli mamy MVD A →→ B, to A musi jednoznacznie identyfikować każdy wiersz w tabeli. W naszym przykładzie, w tabeli DaneKontaktowe mamy MVD ID_Czytelnika →→ Telefon. ID_Czytelnika nie jest nadkluczem (kluczem jest (ID_Czytelnika, Telefon, Email)), więc tabela narusza 4NF.

Gdy rozdzielimy dane na Telefony i Emaile, w tabeli Telefony MVD ID_Czytelnika →→ Telefon staje się trywialna, bo ID_Czytelnika ∪ Telefon = wszystkie atrybuty tabeli. MVD trywialna nie narusza 4NF. Podobnie w tabeli Emaile. Zatem po dekompozycji obie tabele są w 4NF.

20/604NF – warunki szczegółowo

Kiedy MVD jest problemem, a kiedy nie?

  • Warunek 1: tabela musi być w BCNF (to jest spełnione gdy nie ma nielegalnych FD)
  • Warunek 2: dla każdej MVD A →→ B, A musi być nadkluczem
  • Jeśli A →→ B i A jest nadkluczem: MVD jest 'naturalna' – wynika z klucza
  • Jeśli A →→ B i A nie jest nadkluczem: MVD jest 'problemowa' – tworzy produkt kartezjański

W przykładzie: ID_Czyt →→ Telefon – ID_Czyt nie jest nadkluczem (klucz to (ID_Czyt, Telefon, Email)).

Jeśli MVD wynika z klucza – OK. Jeśli nie – trzeba rozdzielić. To cała filozofia 4NF.
Schemat: MVD z nadklucza (OK) vs MVD z nie-klucza (problem)

Warunki 4NF można rozbić na dwa szczegółowe wymagania. Po pierwsze, tabela musi być w BCNF – to znaczy, że nie ma nielegalnych zależności funkcyjnych. To jest warunek wstępny, który zakładamy przed rozważaniem 4NF. Po drugie, dla każdej nietrywialnej MVD A →→ B, A musi być nadkluczem. To jest warunek właściwy dla 4NF.

Kluczowe jest rozróżnienie między MVD "naturalną" (wynikającą z klucza) a "problemową" (nie wynikającą z klucza). Jeśli A jest nadkluczem, to MVD A →→ B jest naturalną konsekwencją struktury klucza – nie ma w niej niczego podejrzanego. Jeśli A nie jest nadkluczem, to MVD wskazuje na istnienie niezależnych list w tabeli, które należy rozdzielić.

W przykładzie DaneKontaktowe, ID_Czytelnika →→ Telefon jest problemowe, bo ID_Czytelnika to nie nadklucz. Natomiast po dekompozycji, w tabeli Telefony, MVD ID_Czytelnika →→ Telefon jest naturalne (choć trywialne), bo ID_Czytelnika w połączeniu z Telefonem tworzy klucz.

21/60Różnica: BCNF vs 4NF

Zestawienie porównawcze

CechaBCNF4NF
EliminujeFD od nie-kluczaMVD od nie-klucza
WarunekX → A ⇒ X = nadkluczA →→ B ⇒ A = nadklucz
DotyczyZależności funkcyjnychZależności wielowartościowych
Przykład naruszeniaID_Czyt → ID_Bib (FD)ID_Czyt →→ Telefon (MVD)
Kiedy potrzebnaNakładające się klucze FDNiezależne listy wartości
Rok1974 (Boyce, Codd)1977 (Fagin)
BCNF → FD muszą wynikać z klucza. 4NF → MVD też muszą wynikać z klucza. 4NF to BCNF dla MVD.
Tabela porównawcza BCNF vs 4NF z kolorowymi wierszami

Porównanie BCNF i 4NF można ująć w prosty schemat: BCNF dotyczy FD (zależności funkcyjnych), 4NF dotyczy MVD (zależności wielowartościowych). BCNF wymaga, aby każdy wyznacznik FD był nadkluczem. 4NF dodaje wymaganie, aby każdy wyznacznik MVD był nadkluczem. To analogiczne podejście do dwóch różnych typów zależności.

W kontekście historycznym: BCNF powstała w 1974 roku jako odpowiedź na ograniczenia 3NF (problem nakładających się kluczy). 4NF pojawiła się trzy lata później (Fagin, 1977) jako odpowiedź na odkrycie MVD. To pokazuje, że teoria normalizacji rozwijała się stopniowo, w miarę odkrywania coraz subtelniejszych typów zależności między danymi.

W praktyce oznacza to, że jeśli tabela jest w BCNF, to nie znaczy automatycznie, że jest w 4NF. Ale jeśli tabela jest w 4NF, to automatycznie jest w BCNF. 4NF jest bardziej restrykcyjna, bo nakłada dodatkowy warunek na MVD. To tak, jakby BCNF była egzaminem z FD, a 4NF egzaminem z FD + MVD.

22/60MVD trywialne i nietrywialne

Nie każda MVD jest problemem

  • MVD trywialna: A →→ B gdzie B ⊆ A lub A ∪ B = R (wszystkie atrybuty)
    • Przykład: (ID_Czyt, Telefon) →→ ID_Czyt – trywialna (bo ID_Czyt jest w lewej stronie)
  • MVD nietrywialna: A →→ B gdzie B nie jest podzbiorem A i A ∪ B ≠ R
    • Przykład: ID_Czyt →→ Telefon – nietrywialna
Trywialne MVD są jak powiedzenie 'woda jest mokra' – zawsze prawdziwe, nikogo nie interesują. Nietrywialne MVD to sedno 4NF.
Diagram: MVD trywialna vs MVD nietrywialna

Nie każda MVD stanowi problem dla 4NF. MVD trywialne to takie, które są zawsze prawdziwe niezależnie od danych. Są dwa przypadki: gdy B ⊆ A (lewa strona zawiera prawą, np. (ID, Telefon) →→ ID) lub gdy A ∪ B = R (wszystkie atrybuty tabeli). MVD trywialne nie wpływają na 4NF, ponieważ nie wskazują na istnienie niezależnych list.

MVD nietrywialne to takie, które nie są trywialne – czyli B nie jest podzbiorem A i A ∪ B ≠ R. To właśnie te MVD są problematyczne w kontekście 4NF. W tabeli DaneKontaktowe, ID_Czytelnika →→ Telefon jest nietrywialne, bo Telefon nie jest podzbiorem {ID_Czytelnika}, a ID_Czytelnika ∪ Telefon nie zawiera Emaila.

Po dekompozycji do 4NF, tabela Telefony ma atrybuty (ID_Czytelnika, Telefon). MVD ID_Czytelnika →→ Telefon jest tutaj trywialna, bo ID_Czytelnika ∪ Telefon = wszystkie atrybuty. To samo dotyczy tabeli Emaile. Dlatego po dekompozycji obie tabele spełniają 4NF.

23/60Dekompozycja do 4NF – zasada ogólna

Dla każdej MVD twórz osobną tabelę

Dla każdej nietrywialnej MVD A →→ B, gdzie A nie jest nadkluczem:

  1. Utwórz tabelę (A, B)
  2. Utwórz tabelę (A, C) gdzie C = R – A – B (pozostałe atrybuty)
  3. Powtórz dla każdej MVD

W przykładzie: ID_Czyt →→ Telefon i ID_Czyt →→ Email

  1. Tabela Telefony: (ID_Czytelnika, Telefon)
  2. Tabela Emaile: (ID_Czytelnika, Email)
Dekompozycja 4NF: dla każdej MVD, twórz osobną tabelę. Telefony osobno, emaile osobno.
Schemat dekompozycji: jedna tabela DaneKontaktowe → dwie tabele: Telefony i Emaile

Algorytm dekompozycji do 4NF jest prosty i powtarzalny: dla każdej nietrywialnej MVD A →→ B, gdzie A nie jest nadkluczem, dzielimy tabelę na dwie: (A, B) i (A, C), gdzie C = R – A – B (pozostałe atrybuty). Następnie powtarzamy proces dla każdej z nowych tabel, aż wszystkie MVD będą trywialne lub wynikać z kluczy.

W przykładzie bibliotecznym, tabela DaneKontaktowe ma dwie MVD: ID_Czyt →→ Telefon i ID_Czyt →→ Email. Stosując algorytm: dla MVD ID_Czyt →→ Telefon tworzymy (ID_Czyt, Telefon, TypTel) i (ID_Czyt, Email). Dla MVD ID_Czyt →→ Email tworzymy (ID_Czyt, Email, TypEmail). Rezultat: trzy tabele (Czytelnicy, Telefony, Emaile), każda w 4NF.

Ważna uwaga: algorytm gwarantuje dekompozycję bezstratną, co oznacza, że złączenie nowych tabel da dokładnie oryginalne dane. Nie tracimy żadnych informacji, a zyskujemy czystą strukturę pozbawioną redundancji i anomalii.

24/60Weryfikacja 4NF po dekompozycji

Sprawdzenie, czy nowe tabele są w 4NF

  • Telefony: (ID_Czytelnika, Telefon) – klucz (ID_Czytelnika, Telefon)
    • ID_Czytelnika →→ Telefon? Tak, ale jest TRYWIALNA: ID_Czyt ∪ Telefon = {ID_Czyt, Telefon} = R
    • MVD trywialna nie narusza 4NF ✔
  • Emaile: (ID_Czytelnika, Email) – analogicznie – MVD trywialna ✔
Po dekompozycji MVD stają się trywialne – bo tabela zawiera tylko te atrybuty, których dotyczy MVD. 4NF spełniona!
Weryfikacja: Telefony (MVD trywialna) i Emaile (MVD trywialna) – obie w 4NF

Weryfikacja 4NF po dekompozycji polega na sprawdzeniu, czy w nowych tabelach nie ma nietrywialnych MVD, które nie wynikają z kluczy. W tabeli Telefony (ID_Czytelnika, Telefon) sprawdzamy: czy istnieje MVD ID_Czytelnika →→ Telefon? Tak, ale jest trywialna, bo ID_Czytelnika ∪ Telefon = wszystkie atrybuty. Zatem 4NF spełniona.

Analogicznie dla tabeli Emaile (ID_Czytelnika, Email): MVD ID_Czytelnika →→ Email jest trywialna z tego samego powodu. Oryginalna tabela Czytelnicy (ID_Czytelnika, Imie, Nazwisko, ID_Miasta) nie ma żadnych MVD – nie ma atrybutów wielokrotnych. Zatem wszystkie trzy tabele są w 4NF.

Weryfikacja jest ważnym krokiem, bo pozwala upewnić się, że dekompozycja nie wprowadziła nowych problemów. W praktyce, jeśli stosujemy algorytm dekompozycji poprawnie, nowe tabele zawsze są w 4NF. Niemniej warto sprawdzić, czy nie pominięto którejś MVD, zwłaszcza gdy tabela miała wiele atrybutów i złożone zależności.

25/604NF w praktyce – jak często potrzebna?

4NF jest rzadziej potrzebna niż BCNF, ale czasem niezbędna

  • MVD występują rzadziej niż FD – dlatego 4NF jest rzadziej potrzebna
  • Typowe sytuacje: dane kontaktowe (wiele telefonów, emaili), role (wiele ról dla użytkownika)
  • Często pomijane w praktyce – programiści akceptują produkt kartezjański
  • Statystyka: ~90% baz danych zatrzymuje się na 3NF, ~9% na BCNF, ~1% na 4NF
4NF to déjà vu – znów rozdzielamy dane na osobne tabele, ale tym razem dla niezależnych zbiorów, nie dla zależności funkcyjnych.
Wykres: 90% (3NF), 9% (BCNF), 1% (4NF) – rzadkość 4NF w praktyce

4NF jest rzadziej potrzebna niż BCNF, ponieważ MVD występują rzadziej niż FD. Szacuje się, że około 90% baz danych zatrzymuje się na 3NF, 9% na BCNF, a tylko 1% dociera do 4NF. To nie znaczy, że 4NF jest nieistotna – znaczy, że w większości przypadków struktura danych jest na tyle prosta, że MVD nie występują.

Typowe sytuacje, w których MVD się pojawiają, to dane kontaktowe (wiele telefonów, emaili), systemy tagowania (wiele tagów dla obiektu), role użytkowników (wiele ról), kategorie produktów (wiele kategorii). Wszędzie tam, gdzie jeden obiekt ma dwie lub więcej niezależnych list wartości, 4NF może być potrzebna.

W wielu komercyjnych systemach 4NF jest pomijana, a programiści akceptują produkt kartezjański jako "cenę za prostotę". Dla małych danych (np. średnio 2 telefony i 2 emaile na czytelnika) różnica jest niewielka. Jednak dla systemów z dużymi wolumenami danych (np. system CRM z milionami klientów) 4NF może przynieść znaczące oszczędności miejsca i poprawić wydajność.

26/60Ćwiczenie 1: zidentyfikuj MVD

Tabela AutorzyKsiazki – trzy niezależne listy

Tabela AutorzyKsiazki: (ISBN, Autor, Kategoria, Jezyk)

Założenie: książka może mieć wielu autorów, wiele kategorii, być w wielu językach.

Czy są MVD? Tak:

  • ISBN →→ Autor
  • ISBN →→ Kategoria
  • ISBN →→ Jezyk

Czy tabela jest w 4NF? NIE – ISBN nie jest nadkluczem.

Ćwiczenie: książka z wieloma autorami, kategoriami i językami – trzy niezależne listy. Trzy MVD, trzy naruszenia 4NF.
Tabela AutorzyKsiazki z zaznaczonymi MVD

Ćwiczenie 1 polega na identyfikacji MVD w tabeli AutorzyKsiazki (ISBN, Autor, Kategoria, Jezyk). Każda książka może mieć wielu autorów, wiele kategorii i być w wielu językach. Są to trzy niezależne listy: autorzy nie zależą od kategorii, kategorie nie zależą od języka, itd. Zatem mamy trzy MVD: ISBN →→ Autor, ISBN →→ Kategoria, ISBN →→ Jezyk.

ISBN nie jest nadkluczem – kluczem jest (ISBN, Autor, Kategoria, Jezyk). Zatem tabela nie jest w 4NF. Rozwiązanie: dekompozycja na trzy tabele: Autorzy (ISBN, Autor), Kategorie (ISBN, Kategoria), Jezyki (ISBN, Jezyk). Każda z tych tabel przechowuje jedną niezależną listę i jest w 4NF.

To ćwiczenie pokazuje, że liczba MVD w tabeli może być większa niż dwie. W tabeli z czterema atrybutami i trzema niezależnymi listami mamy trzy MVD. Każda z nich wymaga osobnej tabeli. W efekcie z jednej tabeli otrzymujemy trzy, co eliminuje produkt kartezjański między wszystkimi trzema listami.

27/60Ćwiczenie 2: zaprojektuj dekompozycję do 4NF

Rozwiązanie – trzy tabele zamiast jednej

Tabela AutorzyKsiazki: (ISBN, Autor, Kategoria, Jezyk)

Dekompozycja:

  1. Autorzy (ISBN, Autor)
  2. Kategorie (ISBN, Kategoria)
  3. Jezyki (ISBN, Jezyk)
Trzy MVD → trzy nowe tabele. Każda tabela przechowuje JEDNĄ niezależną listę.
Dekompozycja: jedna tabela → cztery tabele

Ćwiczenie 2 polega na zaprojektowaniu dekompozycji tabeli AutorzyKsiazki (ISBN, Autor, Kategoria, Jezyk) do 4NF. Mamy trzy MVD: ISBN →→ Autor, ISBN →→ Kategoria, ISBN →→ Jezyk. Stosując algorytm dekompozycji, tworzymy trzy tabele: Autorzy (ISBN, Autor), Kategorie (ISBN, Kategoria), Jezyki (ISBN, Jezyk).

Każda z nowych tabel ma prosty klucz złożony z dwóch atrybutów. W tabeli Autorzy kluczem jest (ISBN, Autor). MVD ISBN →→ Autor jest teraz trywialna, bo ISBN ∪ Autor = wszystkie atrybuty tabeli. Podobnie dla pozostałych tabel. Wszystkie trzy są zatem w 4NF.

Warto zwrócić uwagę na to, że w oryginalnej tabeli produkt kartezjański występuje między trzema listami naraz. Dla książki z 2 autorami, 3 kategoriami i 2 językami, w 4NF mamy 2 + 3 + 2 = 7 wierszy. Przed 4NF: 2 × 3 × 2 = 12 wierszy. Różnica będzie rosnąć wykładniczo z liczbą wartości na każdej liście.

28/60Ćwiczenie 3: czy to narusza 4NF?

Analiza tabeli Czytelnicy z BD_3NF

Tabela Czytelnicy z BD_3NF: (ID_Czyt, Imie, Nazwisko, ID_Miasta, Telefon, Email)

  • Jeśli Telefon i Email są w Czytelnicy – narusza 4NF
  • Jeśli są w osobnych tabelach – 4NF spełniona
Jeśli Telefon i Email są w tej samej tabeli co dane czytelnika – naruszenie 4NF. Jeśli w osobnych – wszystko OK.
Dwa przypadki: naruszenie vs 4NF OK

Ćwiczenie 3 analizuje tabelę Czytelnicy z BD_3NF: (ID_Czyt, Imie, Nazwisko, ID_Miasta, Telefon, Email). Kluczowe pytanie: czy przechowywanie Telefonu i Emaila w tej samej tabeli narusza 4NF? Odpowiedź: tak, jeśli czytelnik może mieć wiele telefonów i wiele emaili.

W tabeli Czytelnicy z BD_3NF zakładaliśmy, że każdy czytelnik ma jeden telefon i jeden email. W takim przypadku nie ma MVD – nie ma niezależnych list, bo każda lista ma dokładnie jeden element. Tabela jest w BCNF i jednocześnie w 4NF. Problem pojawia się dopiero, gdy dopuścimy wiele telefonów i wiele emaili.

To ćwiczenie uczy ważnej lekcji: 4NF nie jest potrzebna automatycznie. Jest potrzebna tylko wtedy, gdy faktycznie występują niezależne listy wartości. Jeśli w systemie biznesowym każdy czytelnik ma dokładnie jeden telefon i jeden email, to 4NF jest spełniona automatycznie. Normalizacja nie powinna być "sztuką dla sztuki" – powinna odpowiadać rzeczywistym potrzebom.

29/60Scenariusz: system kontaktów w bibliotece

Praktyczny przykład – dane kontaktowe czytelników

  • W naszej bibliotece: czytelnicy mogą podać wiele telefonów i wiele emaili
  • Telefony i emaile są niezależne
  • Dodatkowo: każdy telefon ma typ (komórkowy, stacjonarny), każdy email ma typ
  • Problem: jak zaprojektować tabele, żeby uniknąć produktu kartezjańskiego?
System kontaktów: czytelnicy dają nam telefony i emaile. To idealny przypadek dla 4NF.
Schemat: czytelnik z wieloma telefonami i emailami, każdy z typem

Scenariusz systemu kontaktów w bibliotece jest praktycznym przykładem, który pokazuje, jak 4NF znajduje zastosowanie w rzeczywistym systemie. Biblioteka gromadzi dane kontaktowe czytelników: każdy czytelnik może podać wiele numerów telefonów (komórkowy, stacjonarny, służbowy) i wiele adresów email (prywatny, służbowy). Telefony i emaile są od siebie niezależne.

Dodatkowo, każdy telefon ma swój typ (komórkowy, stacjonarny), a każdy email ma swój typ (prywatny, służbowy). To są atrybuty zależne od konkretnego telefonu lub emaila – nie są niezależne. Typ telefonu jest zależny od telefonu, więc nie tworzy osobnej MVD. Podobnie typ emaila jest zależny od emaila.

W projekcie musimy zdecydować, czy przechowywać wszystkie dane w jednej tabeli (wygodnie, ale 4NF naruszona), czy rozdzielić na trzy tabele (bardziej złożone zapytania, ale czysta struktura). To klasyczny kompromis między prostotą a czystością danych, który projektant bazy musi rozważyć.

30/60Pierwsza próba: jedna tabela (naruszająca 4NF)

Tabela DaneKontaktowe – wygodnie, ale źle

Tabela DaneKontaktowe: (ID_Czytelnika, Telefon, Email)

  • Klucz: (ID_Czytelnika, Telefon, Email)
  • BCNF: spełniona (żadnych FD poza kluczem)
  • Ale MVD: ID_Czyt →→ Telefon i ID_Czyt →→ Email
  • ID_Czyt nie jest nadkluczem → naruszenie 4NF
Jedna tabela na wszystko – wygodnie, ale 4NF naruszona.
Tabela DaneKontaktowe z 5 kolumnami

Pierwsza próba projektowa – jedna tabela DaneKontaktowe (ID_Czytelnika, Telefon, Email) – jest wygodna, ale narusza 4NF. Schemat jest prosty, zapytania są łatwe do napisania, a aplikacja może korzystać z jednej tabeli zamiast trzech. Jednak ta wygoda ma swoją cenę: produkt kartezjański i wynikające z niego anomalie.

Z punktu widzenia BCNF tabela jest poprawna: jedyną FD jest (ID_Czytelnika, Telefon, Email) → (ID_Czytelnika, Telefon, Email), która jest trywialna. Nie ma żadnych "nielegalnych" FD. BCNF nie zgłasza zastrzeżeń. Ale 4NF już tak: MVD ID_Czytelnika →→ Telefon i ID_Czytelnika →→ Email nie wynikają z klucza.

To ważna lekcja: BCNF można porównać do kontroli biletów, która sprawdza, czy każdy pasażer ma bilet. Jeśli wszyscy mają bilety, kontrola mówi "OK". Ale kontrola nie sprawdza, czy pasażerowie nie siedzą na cudzych miejscach (produkt kartezjański). 4NF to dodatkowa kontrola, która sprawdza właśnie to.

31/60Przykładowe dane – czytelnicy i ich kontakty

Jan Kowalski i Anna Nowak – dane kontaktowe

Jan Kowalski (ID=1):

  • Telefony: '123-456-789' (komórkowy), '987-654-321' (stacjonarny)
  • Emaile: 3 emaile

Anna Nowak (ID=2):

  • Telefony: '555-111-222' (komórkowy)
  • Emaile: 2 emaile

W tabeli naruszającej 4NF – 6 wierszy dla Jana, 2 dla Anny.

Jan: 2 telefony i 3 emaile = 6 wierszy. Anna: 1 telefon i 2 emaile = 2 wiersze.
Dwie karty: Jan Kowalski (2 telefony, 3 emaile) i Anna Nowak (1 telefon, 2 emaile)

Przykładowi czytelnicy – Jan Kowalski i Anna Nowak – pokazują skalę problemu z 4NF. Jan ma 2 telefony i 3 emaile, co w tabeli naruszającej 4NF daje 6 wierszy. Anna ma 1 telefon i 2 emaile, co daje 2 wiersze. Łącznie: 8 wierszy dla dwojga czytelników. Po normalizacji do 4NF: Jan: 2 + 3 = 5 wierszy, Anna: 1 + 2 = 3 wiersze. Łącznie: 8 wierszy.

W tym przypadku różnica nie jest duża (8 wierszy w obu przypadkach), ale to dlatego, że dane są małe. W rzeczywistym systemie z tysiącami czytelników, każdy średnio z 3 telefonami i 4 emailami, różnica jest znacząca: przed 4NF: 1000 × 3 × 4 = 12 000 wierszy, po 4NF: 1000 × (3 + 4) = 7 000 wierszy.

Co więcej, różnica rośnie proporcjonalnie do iloczynu liczby telefonów i emaili. Dla czytelnika z 10 telefonami i 20 emailami: przed 4NF = 200 wierszy, po 4NF = 30 wierszy. Przy 50 telefonach i 100 emailach: 5000 vs 150 wierszy. To pokazuje, że 4NF jest tym bardziej opłacalna, im więcej wartości wielokrotnych ma obiekt.

32/60Wizualizacja: tabela DaneKontaktowe – dane Jana

6 wierszy dla 2 telefonów i 3 emaili

IDTelefonTypTelEmailTypEmail
1123-456-789Komórkowyjan@example.comPrywatny
1123-456-789Komórkowyjan.kowalski@work.comSłużbowy
1123-456-789Komórkowyj.k@proton.comPrywatny
1987-654-321Stacjonarnyjan@example.comPrywatny
1987-654-321Stacjonarnyjan.kowalski@work.comSłużbowy
1987-654-321Stacjonarnyj.k@proton.comPrywatny
6 wierszy. Telefon '123-456-789' pojawia się 3 razy. Email 'jan@example.com' pojawia się 2 razy.
Tabela z danymi Jana – 6 wierszy, każdy telefon powtórzony 3 razy

Wizualizacja danych Jana Kowalskiego w tabeli naruszającej 4NF pokazuje produkt kartezjański w akcji. Telefon '123-456-789' pojawia się 3 razy (dla każdego emaila), a email 'jan@example.com' pojawia się 2 razy (dla każdego telefonu). W tabeli jest 6 wierszy, każdy z pełną informacją o typie telefonu i typie emaila.

Redundancja jest widoczna gołym okiem: dane o typie telefonu są powtórzone 3 razy (dla '123-456-789') i 3 razy (dla '987-654-321'). To łącznie 6 powtórzeń informacji, która w 4NF wystąpiłaby tylko 2 razy (raz na telefon). Dla 10 telefonów i 20 emaili, typ telefonu byłby powtórzony 20 razy dla każdego telefonu – czysta strata miejsca.

Produkt kartezjański jest szczególnie niebezpieczny, gdy w grę wchodzą dane wrażliwe (np. numery telefonów, adresy email). W przypadku wycieku danych, każdy wiersz zawiera kompletny zestaw danych kontaktowych, a nie tylko jeden fakt. 4NF ogranicza ryzyko, bo każda tabela przechowuje tylko jeden rodzaj danych.

33/60Anomalie w praktyce – przykład zmiany

Zmiana emaila – ryzyko niespójności

Jan zmienia email z 'jan@example.com' na 'jan.nowy@example.com'

  • Trzeba zaktualizować 2 wiersze (dla każdego telefonu)
  • Jeśli zaktualizujemy tylko 1 z 2 wierszy – dane są niespójne
Niespójność: jeden wiersz mówi 'jan@example.com', drugi 'jan.nowy@example.com'. Który jest poprawny? Baza nie wie.
Ilustracja: dwa wiersze – jeden z starym emailem, drugi z nowym – niespójność

Anomalia w praktyce – zmiana emaila Jana z 'jan@example.com' na 'jan.nowy@example.com' – ilustruje ryzyko niespójności. W tabeli naruszającej 4NF trzeba zaktualizować 2 wiersze (dla każdego telefonu). Jeśli jedna z aktualizacji się nie powiedzie, w bazie pozostanie jeden wiersz ze starym emailem i jeden z nowym.

Konsekwencje: biblioteka wysyła powiadomienia na oba adresy – stary (nieaktywny) i nowy. Albo, co gorsza, system wyświetla oba emaile w profilu czytelnika, dezorientując zarówno personel, jak i samego czytelnika. W 4NF zmiana emaila to jeden UPDATE w tabeli Emaile – atomowy, bezpieczny, niezawodny.

Ten przykład pokazuje, że normalizacja to nie tylko teoria, ale praktyczne narzędzie do zapewnienia integralności danych. W środowisku produkcyjnym, gdzie tysiące transakcji są wykonywane równolegle przez wielu użytkowników, ryzyko pominięcia jednej z wielu aktualizacji jest realne. 4NF eliminuje to ryzyko u źródła.

34/60Rozwiązanie 4NF: dekompozycja na trzy tabele

Zamiast jednej – trzy tabele

Zamiast jednej tabeli DaneKontaktowe – trzy tabele:

  1. Czytelnicy (ID_Czytelnika, Imie, Nazwisko, ID_Miasta)
  2. Telefony (ID_Czytelnika, Telefon)
  3. Emaile (ID_Czytelnika, Email)
Trzy tabele zamiast jednej. Telefony przechowuje tylko telefony, Emaile tylko emaile.
Schemat: jedna tabela DaneKontaktowe → trzy tabele

Rozwiązanie 4NF: dekompozycja na trzy tabele – Czytelnicy, Telefony, Emaile. Każda tabela przechowuje jeden rodzaj faktów. Czytelnicy: dane osobowe (stałe, jeden wiersz na czytelnika). Telefony: numery telefonów (wiele wierszy na czytelnika). Emaile: adresy email (wiele wierszy na czytelnika). Żadna tabela nie miesza dwóch niezależnych list.

Po dekompozycji, dodanie nowego telefonu to jeden INSERT w tabeli Telefony. Zmiana emaila to jeden UPDATE w tabeli Emaile. Usunięcie telefonu to jeden DELETE w tabeli Telefony. Każda operacja jest atomowa i dotyczy dokładnie jednego faktu. Nie ma ryzyka pominięcia którejś z wielu operacji, nie ma produktu kartezjańskiego.

Kosztem tej czystości jest konieczność używania JOIN-ów do odczytu wszystkich danych kontaktowych czytelnika. SELECT z JOIN-em trzech tabel (Czytelnicy LEFT JOIN Telefony LEFT JOIN Emaile) daje produkt kartezjański w wyniku – ale to tylko tymczasowy wynik zapytania, a nie struktura danych. To fundamentalna różnica.

35/60Porównanie: przed i po 4NF

Tabela porównawcza – same zalety

AspektPrzed 4NFPo 4NF
Liczba tabel13
Wiersze (Jan)65
Wiersze (Anna)23
RedundancjaWysokaBrak
AnomalieTakNie

*Różnica rośnie wykładniczo z liczbą wartości.

Przy małych danych różnica zerowa. Ale przy 10 telefonach i 20 emailach: 200 vs 30 wierszy.
Tabela porównawcza przed i po 4NF

Porównanie przed i po 4NF pokazuje, że korzyści rosną wraz z ilością danych. Dla Jana (2 telefony, 3 emaile): przed 4NF = 6 wierszy, po 4NF = 5 wierszy (2 + 3). Dla Anny (1 telefon, 2 emaile): przed 4NF = 2 wiersze, po 4NF = 3 wiersze (1 + 2). W przypadku Anny liczba wierszy nawet wzrosła – to dlatego, że dane są małe, a struktura została "rozdzielona".

Dla całej biblioteki z 10 000 czytelników, każdy średnio z 3 telefonami i 4 emailami: przed 4NF: 10 000 × 3 × 4 = 120 000 wierszy. Po 4NF: 10 000 × (3 + 4) = 70 000 wierszy. Oszczędność 50 000 wierszy to nie tylko miejsce na dysku, ale przede wszystkim szybsze indeksowanie, mniejsze zapotrzebowanie na pamięć podręczną i sprawniejsze zapytania.

Co więcej, w 4NF każda tabela ma prostszy indeks (dwie kolumny zamiast pięciu), co przyspiesza operacje wyszukiwania. A brak anomalii oznacza, że programiści mogą pisać prostszy kod aplikacji bez ryzyka niespójności danych. To oszczędność czasu i pieniędzy w dłuższej perspektywie.

36/604NF – dodatkowy przykład: tagi i kategorie książek

Niezależne listy w innym kontekście

Tabela KsiazkiTagiKategorie: (ISBN, Tag, Kategoria)

Rozwiązanie 4NF:

  1. Tagi (ISBN, Tag)
  2. Kategorie (ISBN, Kategoria)
Tagi i kategorie książki – to samo co telefony i emaile. Dwie niezależne listy, dwie osobne tabele.
Schemat: książka z tagami i kategoriami – dwie osobne tabele

Przykład tagów i kategorii książek pokazuje, że 4NF znajduje zastosowanie w wielu kontekstach, nie tylko w danych kontaktowych. Tabela KsiazkiTagiKategorie (ISBN, Tag, Kategoria) przechowuje dwa niezależne fakty: "książka ma tag" i "książka należy do kategorii". Tagi i kategorie są niezależne, więc mamy MVD ISBN →→ Tag i ISBN →→ Kategoria.

Rozwiązanie 4NF: Tagi (ISBN, Tag) i Kategorie (ISBN, Kategoria). Każda tabela przechowuje jedną listę. Produkt kartezjański między tagami a kategoriami znika. Dla książki z 5 tagami i 3 kategoriami: przed 4NF = 15 wierszy, po 4NF = 8 wierszy.

To samo dotyczy wielu innych domen: systemów e-commerce (produkt z wieloma kolorami i rozmiarami), systemów rezerwacji (hotel z wieloma pokojami i udogodnieniami), platform społecznościowych (użytkownik z wieloma grupami i zainteresowaniami). Wszędzie tam, gdzie jeden obiekt ma wiele niezależnych list wartości, 4NF jest odpowiedzią.

37/604NF w kontekście całego schematu biblioteki

Ostateczny schemat – 8 tabel w 4NF

Po dodaniu 4NF, nasz schemat biblioteki:

  • 6 dotychczasowych tabel + Telefony + Emaile
  • Łącznie: 8 tabel, każda w 4NF
Nasza biblioteka: 8 tabel, każda w 4NF.
Schemat bazy biblioteki – 8 tabel

Ostateczny schemat biblioteki po dodaniu 4NF składa się z 8 tabel: 6 dotychczasowych (Czytelnicy, Miasta, Ksiazki, Wypozyczenia, Opiekunowie, Przypisania_BCNF) plus 2 nowe (Telefony, Emaile). Każda z tych tabel jest w 4NF, co oznacza, że żadna nie zawiera nietrywialnych MVD niewynikających z kluczy.

W porównaniu do schematu z BCNF, dodaliśmy dwie tabele, ale zyskaliśmy czystość danych i brak anomalii. Czytelnicy nie przechowują już telefonów ani emaili – te informacje są w osobnych tabelach, połączonych kluczami obcymi. Każdy fakt jest przechowywany dokładnie raz, w odpowiedniej tabeli.

To dobry moment, aby podkreślić, że normalizacja to proces iteracyjny. Nie trzeba od razu projektować bazy w 4NF – można zacząć od 3NF, potem sprawdzić BCNF, a na końcu 4NF. Każdy krok dodaje czystości, ale też złożoności. Decyzja o tym, jak daleko iść, zależy od konkretnych wymagań systemu.

38/60Ćwiczenie: znajdź MVD w podanej tabeli

Tabela StudenciZainteresowania

Tabela StudenciZainteresowania: (ID_Studenta, Przedmiot, Hobby, JezykObcy)

Pytania:

  1. Czy są MVD? Tak – ID_Studenta →→ Przedmiot, →→ Hobby, →→ JezykObcy
  2. Czy tabela jest w 4NF? NIE
  3. Zaprojektuj dekompozycję
Samodzielne ćwiczenie: trzy MVD, trzy osobne tabele.
Tabela StudenciZainteresowania z trzema MVD

Ćwiczenie z tabelą StudenciZainteresowania (ID_Studenta, Przedmiot, Hobby, JezykObcy) to samodzielne zadanie do przećwiczenia. Mamy trzy niezależne listy dla każdego studenta: przedmioty, hobby i języki obce. Trzy MVD: ID_Studenta →→ Przedmiot, ID_Studenta →→ Hobby, ID_Studenta →→ JezykObcy.

Rozwiązanie: dekompozycja na trzy tabele: Przedmioty (ID_Studenta, Przedmiot), Hobby (ID_Studenta, Hobby), JezykiObce (ID_Studenta, JezykObcy). Każda tabela w 4NF. Dla studenta z 4 przedmiotami, 3 hobby i 2 językami: przed 4NF = 24 wiersze, po 4NF = 9 wierszy.

Zachęcamy do samodzielnego przeanalizowania innych przykładów: lekarz z wieloma specjalizacjami i gabinetami, klient z wieloma adresami i numerami telefonów, produkt z wieloma wariantami i kolorami. Im więcej przykładów przerobisz, tym łatwiej będzie Ci rozpoznawać MVD w rzeczywistych systemach.

39/60Ćwiczenie: zaprojektuj bazę noclegów w 4NF

System rezerwacji noclegów

Tabela HoteleWyposazenie: (ID_Hotelu, NazwaHotelu, Pokoj, Udogodnienie)

Dekompozycja:

  1. Hotele (ID_Hotelu, NazwaHotelu)
  2. Pokoje (ID_Hotelu, Pokoj)
  3. Udogodnienia (ID_Hotelu, Udogodnienie)
Hotel ma listę pokoi i listę udogodnień – rozdziel na osobne tabele.
Schemat: hotel z pokojami i udogodnieniami – trzy osobne tabele

Ćwiczenie z bazą noclegów: tabela HoteleWyposazenie (ID_Hotelu, NazwaHotelu, Pokoj, Udogodnienie) zawiera dane o hotelach. Każdy hotel ma nazwę, listę pokoi i listę udogodnień. Pokój i udogodnienie są niezależne – liczba pokoi nie ma związku z liczbą udogodnień. Mamy MVD: ID_Hotelu →→ Pokoj i ID_Hotelu →→ Udogodnienie.

Rozwiązanie: dekompozycja na trzy tabele: Hotele (ID_Hotelu, NazwaHotelu), Pokoje (ID_Hotelu, Pokoj), Udogodnienia (ID_Hotelu, Udogodnienie). Każda tabela w 4NF. Dla hotelu z 10 pokojami i 5 udogodnieniami: przed 4NF = 50 wierszy, po 4NF = 15 wierszy.

To ćwiczenie pokazuje, że 4NF jest uniwersalna – nie zależy od domeny, tylko od struktury zależności. W każdym systemie, gdzie jeden obiekt ma dwie lub więcej niezależnych list wartości, 4NF jest potrzebna. Umiejętność rozpoznawania MVD w różnych kontekstach to kluczowa kompetencja projektanta baz danych.

40/60Podsumowanie: kiedy stosować 4NF?

Praktyczne wskazówki

  • Gdy przechowujesz niezależne listy dla tego samego obiektu
  • Gdy widzisz produkt kartezjański w danych
  • Gdy INSERT/UPDATE/DELETE wymagają modyfikacji wielu wierszy
4NF jest potrzebna, gdy dwa 'wiele' są w tej samej tabeli i są niezależne.
Lista kontrolna: kiedy stosować 4NF

Podsumowując: 4NF stosujemy, gdy w tabeli występują niezależne listy wartości dla tego samego obiektu. Objawy ostrzegawcze to produkt kartezjański w danych (gwałtowny wzrost liczby wierszy), konieczność wykonywania wielu INSERT-ów/UPDATE-ów/DELETE-ów dla jednej logicznej operacji oraz widoczna redundancja (te same wartości powtarzane wielokrotnie).

Nie stosujemy 4NF, gdy listy są zależne (np. telefon i typ telefonu – typ zależy od telefonu) lub gdy koszt JOIN-ów przewyższa korzyści z eliminacji redundancji. Dla małych danych (np. średnio 1-2 wartości na listę) 4NF może być przesadą, choć czystość struktury jest zawsze wartością samą w sobie.

Pamiętaj: normalizacja to narzędzie, nie cel. Celem jest integralność i spójność danych. Jeśli 4NF pomaga ten cel osiągnąć – stosuj ją. Jeśli przeszkadza (np. dramatycznie spowalnia zapytania) – rozważ kompromis. Dobry projektant baz danych wie, kiedy normy są pomocne, a kiedy stanowią przeszkodę.

41/60Krok 1: Tabela z naruszeniem 4NF (ale w BCNF)

CREATE TABLE – przykład naruszenia

-- Tabela DaneKontaktowe - narusza 4NF (MVD), ale jest w BCNF
CREATE TABLE DaneKontaktowe (
    ID_Czytelnika INT NOT NULL,
    Telefon       VARCHAR(20) NOT NULL,
    Email         VARCHAR(100) NOT NULL,
    PRIMARY KEY (ID_Czytelnika, Telefon, Email)
);
-- BCNF: brak FD poza kluczem - tabela w BCNF
-- Ale MVD: ID_Czyt ->-> Telefon i ID_Czyt ->-> Email - naruszenie 4NF!
Tabela w BCNF (brak FD poza kluczem), ale 4NF naruszona przez MVD. BCNF nie wychwytuje MVD.
CREATE TABLE DaneKontaktowe – kod SQL

Implementacja w MariaDB rozpoczyna się od utworzenia tabeli naruszającej 4NF – DaneKontaktowe (ID_Czytelnika, Telefon, Email). Kod CREATE TABLE jest prosty, a klucz główny jest złożony ze wszystkich trzech kolumn. Z punktu widzenia składni SQL wszystko jest poprawne – MariaDB nie ostrzeże nas przed MVD, bo system zarządzania bazą danych nie analizuje zależności wielowartościowych.

To ważny punkt: normalizacja jest zadaniem projektanta, nie systemu bazodanowego. MariaDB (ani żaden inny popularny RDBMS) nie sprawdzi automatycznie, czy tabela jest w 4NF. To odpowiedzialność projektanta, aby przeanalizować zależności i zaprojektować tabelę zgodnie z regułami normalizacji.

W kodzie SQL widać, że tabela jest w BCNF – nie ma FD poza kluczem. Komentarz ostrzega przed MVD, które naruszają 4NF. W praktyce warto dodawać takie komentarze w kodzie DDL, aby dokumentować, dlaczego tabela ma taką, a nie inną strukturę i jakie zależności zostały wzięte pod uwagę.

42/60Krok 2: Wstawienie danych do tabeli z naruszeniem

INSERT – 6 wierszy dla 2 telefonów i 3 emaili

-- Wstawienie danych dla Jana Kowalskiego (ID=1)
-- 2 telefony x 3 emaile = 6 wierszy!
INSERT INTO DaneKontaktowe VALUES
    (1, '123-456-789', 'Komórkowy', 'jan@example.com', 'Prywatny'),
    (1, '123-456-789', 'Komórkowy', 'jan.kowalski@work.com', 'Służbowy'),
    (1, '123-456-789', 'Komórkowy', 'j.k@proton.com', 'Prywatny'),
    (1, '987-654-321', 'Stacjonarny', 'jan@example.com', 'Prywatny'),
    (1, '987-654-321', 'Stacjonarny', 'jan.kowalski@work.com', 'Służbowy'),
    (1, '987-654-321', 'Stacjonarny', 'j.k@proton.com', 'Prywatny');
-- 6 wierszy dla 2 telefonów i 3 emaili - produkt kartezjański
6 wierszy. Każdy telefon sparowany z każdym emailem.
INSERT do DaneKontaktowe – 6 wierszy SQL

Wstawienie danych do tabeli naruszającej 4NF pokazuje skalę redundancji w praktyce. Dla Jana Kowalskiego (2 telefony, 3 emaile) musimy wykonać 6 INSERT-ów, każdy z pełnym zestawem danych. Kod jest długi, podatny na błędy (łatwo pominąć jedną kombinację) i nieczytelny – 6 wierszy dla danych, które logicznie są tylko 2 + 3 = 5 faktami.

W kodzie SQL widać wyraźnie powtarzające się wartości: telefon '123-456-789' z typem 'Komórkowy' pojawia się 3 razy, email 'jan@example.com' z typem 'Prywatny' pojawia się 2 razy. To marnotrawstwo przestrzeni dyskowej i pasma sieciowego przy przesyłaniu danych.

Dla porównania, po dekompozycji do 4NF ten sam zestaw danych wymaga 2 INSERT-ów do tabeli Telefony i 3 INSERT-ów do tabeli Emaile. Łącznie 5 INSERT-ów, każdy prosty i czytelny. Różnica w objętości kodu SQL jest oczywista – 6 złożonych wierszy vs 5 prostych wierszy.

43/60Krok 3: Rozdzielenie na dwie tabele – 4NF

CREATE TABLE Telefony i CREATE TABLE Emaile

-- Tabela Telefony - osobna lista telefonów
CREATE TABLE Telefony (
    ID_Czytelnika INT NOT NULL,
    Telefon       VARCHAR(20) NOT NULL,
    TypTelefonu   VARCHAR(15) DEFAULT 'Komórkowy',
    PRIMARY KEY (ID_Czytelnika, Telefon),
    FOREIGN KEY (ID_Czytelnika) REFERENCES Czytelnicy(ID_Czytelnika)
);

-- Tabela Emaile - osobna lista emaili
CREATE TABLE Emaile (
    ID_Czytelnika INT NOT NULL,
    Email         VARCHAR(100) NOT NULL,
    TypEmaila     VARCHAR(15) DEFAULT 'Prywatny',
    PRIMARY KEY (ID_Czytelnika, Email),
    FOREIGN KEY (ID_Czytelnika) REFERENCES Czytelnicy(ID_Czytelnika)
);
-- Każda tabela przechowuje JEDEN niezależny fakt
Telefony i Emaile – dwie osobne tabele. Każda przechowuje jeden niezależny fakt. 4NF spełniona.
CREATE TABLE Telefony i Emaile – kod SQL

Rozdzielenie na dwie tabele – Telefony i Emaile – to sedno implementacji 4NF. Każda tabela ma klucz główny złożony z ID_Czytelnika i odpowiednio Telefon lub Email. Klucz obcy do tabeli Czytelnicy zapewnia integralność referencyjną: nie można dodać telefonu dla nieistniejącego czytelnika.

Warto zwrócić uwagę na atrybuty TypTelefonu i TypEmaila. Są one funkcyjnie zależne od odpowiednio telefonu i emaila – nie tworzą MVD. TypTelefonu zależy od konkretnego numeru telefonu, a nie od czytelnika. Dlatego są one przechowywane w tej samej tabeli co telefon/email, a nie w osobnej tabeli.

Po tej dekompozycji, każda tabela przechowuje jeden niezależny fakt. Telefony: "czytelnik ma numer telefonu o określonym typie". Emaile: "czytelnik ma adres email o określonym typie". Żadna tabela nie miesza dwóch niezależnych faktów, więc 4NF jest spełniona.

44/60Krok 4: Wstawianie danych po 4NF

INSERT – 5 wierszy zamiast 6

-- Wstawienie 2 telefonów - 2 wiersze (zamiast 6 wcześniej)
INSERT INTO Telefony VALUES
    (1, '123-456-789', 'Komórkowy'),
    (1, '987-654-321', 'Stacjonarny');

-- Wstawienie 3 emaili - 3 wiersze (zamiast 6 wcześniej)
INSERT INTO Emaile VALUES
    (1, 'jan@example.com', 'Prywatny'),
    (1, 'jan.kowalski@work.com', 'Służbowy'),
    (1, 'j.k@proton.com', 'Prywatny');
-- Razem: 5 wierszy zamiast 6 - brak produktu kartezjańskiego
5 wierszy zamiast 6. Przy 10 telefonach i 20 emailach: 30 wierszy zamiast 200.
INSERT do Telefony i Emaile – 5 wierszy SQL

Wstawianie danych po 4NF pokazuje zalety nowej struktury. Dwa INSERT-y do tabeli Telefony (dla dwóch numerów) i trzy INSERT-y do tabeli Emaile (dla trzech adresów). Łącznie 5 wierszy zamiast 6. Każdy wiersz jest prosty, zawiera tylko istotne dane, bez redundantnych powtórzeń.

Przy większych danych różnica jest jeszcze bardziej widoczna. Dla czytelnika z 10 telefonami i 20 emailami: przed 4NF = 200 INSERT-ów, po 4NF = 30 INSERT-ów. To 170 INSERT-ów mniej – oszczędność czasu przy wstawianiu danych i mniejsze obciążenie dziennika transakcyjnego bazy danych.

Dodatkowo, po 4NF możemy dodać telefon bez emaila (lub email bez telefonu) – nie jesteśmy zmuszeni do tworzenia sztucznych kombinacji. Nowy czytelnik może mieć tylko numer telefonu, a emaile dodać później. To naturalne i zgodne z rzeczywistością biznesową.

45/60Krok 5: Test anomalii INSERT po 4NF

Jeden INSERT zamiast trzech

-- Po 4NF: dodajemy JEDEN wiersz w Telefony
INSERT INTO Telefony (ID_Czytelnika, Telefon, TypTelefonu)
VALUES (1, '555-123-456', 'Komórkowy');
-- Jeden INSERT zamiast trzech
Jeden INSERT zamiast trzech. I czytelnik może mieć telefon bez emaila.
INSERT do Telefony – jeden wiersz SQL

Test anomalii INSERT po 4NF: dodanie nowego telefonu '555-123-456' dla czytelnika to jeden INSERT w tabeli Telefony. Jeden wiersz, jedna operacja, zero ryzyka. Nie trzeba tworzyć kombinacji z emailami, nie trzeba sprawdzać, ile emaili ma czytelnik. Po prostu: INSERT INTO Telefony VALUES (1, '555-123-456', 'Komórkowy').

Przed 4NF ten sam telefon wymagałby INSERT-ów dla każdego emaila czytelnika. Jan ma 3 emaile → 3 INSERT-y. Gdyby Jan miał 50 emaili → 50 INSERT-ów. Liczba INSERT-ów zależy od liczby emaili, które są niezależne od telefonu – to absurdalna zależność, którą 4NF eliminuje.

Co więcej, po 4NF możemy dodać telefon dla czytelnika, który nie ma jeszcze żadnego emaila. W starej strukturze było to niemożliwe, bo klucz główny wymagał zarówno telefonu, jak i emaila. 4NF daje nam elastyczność, której BCNF nie zapewnia.

46/60Krok 6: Test anomalii UPDATE po 4NF

Jeden UPDATE zamiast trzech

-- Po 4NF: aktualizujemy JEDEN wiersz w Telefony
UPDATE Telefony
SET Telefon = '111-222-333'
WHERE ID_Czytelnika = 1 AND Telefon = '123-456-789';
-- Jeden UPDATE zamiast trzech
Jeden UPDATE = jedna zmiana. Proste, bezpieczne, spójne.
UPDATE Telefony – jeden wiersz SQL

Test anomalii UPDATE po 4NF: zmiana numeru telefonu to jeden UPDATE w tabeli Telefony. UPDATE Telefony SET Telefon = '111-222-333' WHERE ID_Czytelnika = 1 AND Telefon = '123-456-789'. Jedna operacja, atomowa, bezpieczna. Niezależnie od tego, ile emaili ma czytelnik.

Przed 4NF ten sam UPDATE wymagał modyfikacji wielu wierszy – po jednym dla każdego emaila. Ryzyko niespójności było realne: jeśli baza danych ulegnie awarii podczas aktualizacji, część wierszy będzie miała stary numer, a część nowy. W 4NF takie ryzyko nie istnieje.

Dodatkowo, po 4NF UPDATE jest szybszy, bo dotyczy tylko jednego wiersza. Nie wymaga skanowania całej tabeli w poszukiwaniu wszystkich wierszy z danym numerem telefonu. Indeks na kolumnie Telefon szybko znajdzie odpowiedni wiersz, a aktualizacja jest błyskawiczna.

47/60Krok 7: Test anomalii DELETE po 4NF

Jeden DELETE zamiast dwóch

-- Po 4NF: usuwamy JEDEN wiersz w Emaile
DELETE FROM Emaile
WHERE ID_Czytelnika = 1 AND Email = 'jan.kowalski@work.com';
-- Jeden DELETE zamiast dwóch
Usuwasz emaile? Telefony zostają. Każda tabela chroni swoje dane.
DELETE z Emaile – jeden wiersz SQL

Test anomalii DELETE po 4NF: usunięcie emaila to jeden DELETE w tabeli Emaile. DELETE FROM Emaile WHERE ID_Czytelnika = 1 AND Email = 'jan.kowalski@work.com'. Jedna operacja, jeden wiersz. Telefony czytelnika pozostają nienaruszone – usunięcie emaila nie wpływa na informacje o telefonach.

Przed 4NF usunięcie emaila wymagało usunięcia wszystkich wierszy z tym emailem – po jednym dla każdego telefonu. Dwa DELETE-y dla czytelnika z 2 telefonami, 50 DELETE-ów dla czytelnika z 50 telefonami. Ryzyko pominięcia któregoś DELETE-a i pozostawienia niespójnych danych.

Co ważne, po 4NF możemy bezpiecznie usunąć wszystkie emaile czytelnika (np. czytelnik zrezygnował z korespondencji), nie tracąc informacji o jego telefonach. W starej strukturze usunięcie ostatniego emaila skutkowałoby usunięciem wszystkich wierszy, a wraz z nimi – informacji o telefonach. To nieodwracalna utrata danych.

48/60Krok 8: Zapytania po 4NF – JOIN-y

JOIN daje produkt kartezjański w wyniku – to OK

-- Pobranie wszystkich danych kontaktowych czytelnika
SELECT c.Imie, c.Nazwisko, t.Telefon, t.TypTelefonu, e.Email, e.TypEmaila
FROM Czytelnicy c
LEFT JOIN Telefony t ON c.ID_Czytelnika = t.ID_Czytelnika
LEFT JOIN Emaile e ON c.ID_Czytelnika = e.ID_Czytelnika
WHERE c.ID_Czytelnika = 1;
-- To zapytanie daje produkt kartezjański w wyniku JOIN-a
-- To jest OK - to tylko wynik zapytania, nie struktura danych!
JOIN daje produkt kartezjański w wynikach – ale to tylko tymczasowe. W strukturze danych nie ma redundancji.
SELECT z JOIN – SQL łączący trzy tabele

Zapytania po 4NF wymagają JOIN-ów, ale to nie jest wada – to naturalna konsekwencja rozdzielenia niezależnych faktów. SELECT z LEFT JOIN trzech tabel (Czytelnicy, Telefony, Emaile) daje produkt kartezjański w wyniku, ale to tylko tymczasowa struktura – nie ma redundancji w danych źródłowych.

Warto podkreślić różnicę między produktem kartezjańskim w strukturze danych (złym) a produktem kartezjańskim w wyniku zapytania (neutralnym). W pierwszym przypadku dane są przechowywane redundantnie i podatne na anomalie. W drugim przypadku produkt kartezjański powstaje na żądanie, tylko na czas trwania zapytania, i nie wpływa na integralność danych.

MariaDB optymalizuje JOIN-y bardzo efektywnie, zwłaszcza gdy kolumny JOIN-u są indeksowane. W praktyce, dla dobrze zaprojektowanej bazy, zapytania z JOIN-ami są szybkie i wydajne. Koszt JOIN-ów jest zazwyczaj akceptowalny w porównaniu do korzyści z eliminacji redundancji i anomalii.

49/60Krok 9: Zaawansowane zapytania – GROUP_CONCAT

Czytelne wyniki bez produktu kartezjańskiego

-- Jeden wiersz na czytelnika z listami
SELECT c.Imie, c.Nazwisko,
       GROUP_CONCAT(DISTINCT t.Telefon) AS Telefony,
       GROUP_CONCAT(DISTINCT e.Email) AS Emaile
FROM Czytelnicy c
LEFT JOIN Telefony t ON c.ID_Czytelnika = t.ID_Czytelnika
LEFT JOIN Emaile e ON c.ID_Czytelnika = e.ID_Czytelnika
GROUP BY c.ID_Czytelnika;
-- Wynik: jeden wiersz na czytelnika
GROUP_CONCAT – zamienia produkt kartezjański w czytelne listy.
SELECT z GROUP_CONCAT – SQL

Funkcja GROUP_CONCAT w MariaDB jest niezwykle przydatna po normalizacji do 4NF. Pozwala na przekształcenie wielu wierszy w jedną listę wartości, co daje czytelny wynik zapytania bez produktu kartezjańskiego. Dla czytelnika z 2 telefonami i 3 emailami, GROUP_CONCAT zwróci jeden wiersz z listą telefonów i listą emaili.

Zapytanie z GROUP_CONCAT i DISTINCT gwarantuje, że w liście nie ma duplikatów. W przykładzie, GROUP_CONCAT(DISTINCT t.Telefon) zwróci '123-456-789,987-654-321' – jeden wiersz z dwoma numerami. Podobnie dla emaili. Wynik jest czytelny i zwięzły.

Warto pamiętać, że GROUP_CONCAT ma ograniczenie długości (domyślnie 1024 znaki, można zwiększyć do 8192). Dla bardzo długich list może być konieczne użycie innych technik (np. aplikacja kliencka scala wyniki). Mimo to, w większości przypadków GROUP_CONCAT jest idealnym narzędziem do prezentacji danych po normalizacji.

50/60Krok 10: Weryfikacja 4NF – czy wszystkie MVD są trywialne?

Sprawdzenie formalne 4NF

-- Sprawdźmy, czy Telefony są w 4NF
-- Atrybuty: ID_Czytelnika, Telefon, TypTelefonu
-- Klucz: (ID_Czytelnika, Telefon)
-- MVD: ID_Czytelnika ->-> Telefon
-- Czy ID_Czytelnika jest nadkluczem? NIE
-- Ale MVD jest TRYWIALNA: ID_Czyt ∪ Telefon = wszystkie atrybuty ✔
-- 4NF spełniona!

-- To samo dla Emaile: MVD trywialna ✔
MVD trywialne – bo tabela zawiera tylko atrybuty z MVD. 4NF spełniona.
Weryfikacja 4NF – SQL z komentarzami

Weryfikacja 4NF w SQL polega na sprawdzeniu, czy w tabeli występują nietrywialne MVD. W MariaDB nie ma bezpośredniego polecenia do wykrywania MVD, ale można to zrobić analizując strukturę tabeli i zależności między atrybutami. W praktyce, jeśli tabela ma tylko jeden klucz kandydujący i wszystkie atrybuty są od niego zależne, to 4NF jest spełniona.

Dla tabeli Telefony: atrybuty to ID_Czytelnika, Telefon, TypTelefonu. Klucz: (ID_Czytelnika, Telefon). MVD ID_Czytelnika →→ Telefon? Tak, ale jest trywialna, bo ID_Czyt ∪ Telefon = R. Podobnie dla Emaile. Zatem obie tabele są w 4NF.

W komentarzach SQL warto udokumentować, dlaczego dana tabela jest w 4NF. To pomaga innym programistom zrozumieć strukturę i uniknąć przypadkowego naruszenia normalizacji przy późniejszych modyfikacjach schematu.

51/60Krok 11: Porównanie wydajności – przed i po 4NF

Oszczędność miejsca i operacji

-- Scenariusz: 10 czytelników, średnio 3 telefony i 4 emaile
-- Przed 4NF: 10 × 3 × 4 = 120 wierszy
-- Po 4NF: 10 × 3 + 10 × 4 = 70 wierszy
-- Oszczędność: 50 wierszy (42% mniej!)
4NF to nie tylko czystość danych – to też oszczędność miejsca.
Porównanie wydajności – tabela z danymi liczbowymi

Porównanie wydajności przed i po 4NF: dla scenariusza z 10 czytelnikami, każdy średnio z 3 telefonami i 4 emailami, przed 4NF mamy 10 × 3 × 4 = 120 wierszy. Po 4NF: 10 × 3 + 10 × 4 = 70 wierszy. Oszczędność 50 wierszy (42% mniej). Przy skali 10 000 czytelników: 120 000 vs 70 000 wierszy – oszczędność 50 000 wierszy.

Oszczędność miejsca to nie tylko mniej danych na dysku. To również mniejsze indeksy (szybsze wyszukiwanie), mniejsze zapotrzebowanie na pamięć podręczną (więcej danych mieści się w RAM), szybsze operacje INSERT/UPDATE/DELETE (mniej wierszy do modyfikacji) i szybsze backup'y.

Warto jednak pamiętać, że zapytania SELECT z JOIN-ami mogą być wolniejsze niż SELECT z jednej tabeli. To kompromis: szybkie zapisy (INSERT/UPDATE/DELETE) kosztem wolniejszych odczytów (SELECT z JOIN). Dla systemów z częstymi zapisami i rzadkimi odczytami 4NF jest korzystna. Dla systemów z częstymi odczytami może być mniej opłacalna.

52/60Krok 12: Typowe błędy przy implementacji 4NF

Czego unikać?

-- Błąd 1: Zapominamy o kluczu obcym
-- Błąd 2: Zbyt wiele tabel - normalizacja przesadna
-- Błąd 3: Mylenie FD z MVD
-- Błąd 4: Zakładanie MVD tam, gdzie ich nie ma
Cztery typowe błędy: brak FK, przesadna normalizacja, mylenie FD/MVD, zakładanie MVD bez podstaw.
Lista typowych błędów

Typowe błędy przy implementacji 4NF: (1) Brak klucza obcego – Telefony.ID_Czytelnika musi być FK do Czytelnicy.ID_Czytelnika. Bez tego można dodać telefon dla nieistniejącego czytelnika, co narusza integralność. (2) Przesadna normalizacja – dzielenie tabeli, która nie ma MVD, tylko dlatego, że "tak wypada". Normalizacja ma sens tylko gdy jest uzasadniona.

(3) Mylenie FD z MVD – to najczęstszy błąd. FD: ID_Czyt → Nazwisko (jedno nazwisko). MVD: ID_Czyt →→ Telefon (wiele telefonów). FD może wymagać osobnej tabeli (jeśli nie wynika z klucza), ale z innych powodów niż MVD. Mylenie ich prowadzi do błędnej dekompozycji.

(4) Zakładanie MVD tam, gdzie ich nie ma. Nie każda tabela z wieloma wartościami ma MVD. Jeśli wartości są zależne (np. telefon i typ telefonu), to nie ma MVD – jest zwykła tabela z atrybutami. MVD wymaga niezależności list. Bez niezależności nie ma problemu i nie trzeba normalizować.

53/60Porównanie postaci normalnych (1NF-4NF)

Mapa normalizacji – od 1NF do 4NF

PostaćEliminujeRok
1NFNieatomowe wartości1970
2NFCzęściowe zależności1971
3NFPrzechodnie zależności1971
BCNFNakładające się klucze (FD)1974
4NFWielowartościowe zależności1977
Każda postać normalna rozwiązuje konkretny problem. 4NF to krok 5 z 6.
Tabela porównawcza postaci normalnych od 1NF do 4NF

Porównanie postaci normalnych od 1NF do 4NF pokazuje ewolucję teorii normalizacji. Każda postać normalna rozwiązuje konkretny problem: 1NF – atomowość, 2NF – zależności częściowe, 3NF – zależności przechodnie, BCNF – nakładające się klucze FD, 4NF – zależności wielowartościowe. Każda kolejna postać jest bardziej restrykcyjna od poprzedniej.

Warto zapamiętać, że normalizacja to hierarchia: każda tabela w 4NF jest automatycznie w BCNF, 3NF, 2NF i 1NF. Ale tabela w 3NF nie musi być w BCNF, a tabela w BCNF nie musi być w 4NF. Im wyższa postać normalna, tym więcej warunków musi spełniać tabela.

Rok 1977 (4NF, Fagin) to 7 lat po pierwszej publikacji Codda o modelu relacyjnym. To pokazuje, że teoria normalizacji rozwijała się stopniowo, w miarę odkrywania coraz subtelniejszych zależności. Dziś normalizacja jest uznaną i dojrzałą dziedziną, ale wciąż wymaga od projektanta dogłębnego zrozumienia zależności w danych.

54/60Podsumowanie 4NF w 5 punktach

Co musisz zapamiętać?

  1. 4NF eliminuje MVD – gdy jeden obiekt ma wiele niezależnych list
  2. MVD ≠ FD – MVD daje zbiór wartości, FD daje jedną wartość
  3. Objawy: produkt kartezjański, redundancja, anomalie
  4. Rozwiązanie: osobne tabele dla każdej listy
  5. Warunek: tabela musi być w BCNF
5 punktów: MVD, produkt kartezjański, osobne tabele, BCNF jako podstawa, niezależność list.
5 punktów podsumowania z ikonami

Podsumowanie 4NF w 5 punktach: (1) 4NF eliminuje MVD, czyli sytuacje, gdy jeden obiekt ma wiele niezależnych list wartości. (2) MVD różni się od FD – FD daje jedną wartość, MVD daje zbiór wartości. (3) Objawem naruszenia 4NF jest produkt kartezjański w danych i konieczność wykonywania wielu operacji DML dla jednej logicznej zmiany.

(4) Rozwiązaniem jest podział tabeli na osobne tabele dla każdej niezależnej listy. W przykładzie bibliotecznym: Telefony i Emaile osobno. (5) Warunkiem koniecznym jest, aby tabela była w BCNF. 4NF = BCNF + warunek na MVD. Bez BCNF nie ma 4NF.

Te 5 punktów warto zapamiętać jako checklistę przed podjęciem decyzji o normalizacji do 4NF. Jeśli wszystkie punkty są spełnione, 4NF jest prawdopodobnie potrzebna. Jeśli któryś nie jest spełniony, 4NF nie jest wymagana.

55/60Kiedy stosować 4NF, a kiedy nie?

Praktyczne wskazówki

STOSUJ 4NF, gdy:

  • Przechowujesz niezależne listy
  • Widzisz produkt kartezjański

NIE STOSUJ 4NF, gdy:

  • Listy są zależne
  • Koszt JOIN-ów przewyższa zyski
4NF to wybór – czystość danych vs prostota zapytań.
Dwie kolumny: STOSUJ vs NIE STOSUJ

Kiedy stosować 4NF? Gdy masz niezależne listy wartości dla tego samego obiektu i widzisz produkt kartezjański w danych. Kiedy nie stosować? Gdy listy są zależne (np. telefon i typ telefonu) lub gdy koszt JOIN-ów przewyższa korzyści z eliminacji redundancji. Decyzja o normalizacji to zawsze kompromis.

W praktyce, dla systemów z małą liczbą wartości wielokrotnych (np. średnio 1-2 telefony, 1-2 emaile), 4NF może być przesadą. Dla systemów z dużą liczbą wartości (np. system CRM z wieloma kanałami komunikacji) 4NF jest koniecznością. Kluczem jest zrozumienie skali danych i wymagań biznesowych.

Pamiętaj: 4NF to narzędzie, a nie dogma. Jeśli Twoja baza danych działa dobrze w 3NF lub BCNF, nie musisz normalizować do 4NF. Normalizacja ma służyć integralności danych, a nie być celem samym w sobie. Dobry projektant wie, kiedy zakończyć normalizację.

56/60Koszt 4NF – więcej tabel, więcej JOIN-ów

Zalety i wady 4NF

Zalety: brak redundancji, brak anomalii, czysta struktura, oszczędność miejsca.

Wady: więcej tabel, więcej JOIN-ów, potrzeba GROUP_CONCAT, większa złożoność.

4NF to jak sprzątanie pokoju – im czyściej, tym trudniej znaleźć rzeczy.
Waga: zalety vs wady 4NF

Koszt 4NF to przede wszystkim więcej tabel i więcej JOIN-ów w zapytaniach. Zamiast jednej tabeli DaneKontaktowe mamy trzy: Czytelnicy, Telefony, Emaile. Każde zapytanie pobierające pełne dane kontaktowe wymaga LEFT JOIN dwóch dodatkowych tabel. To zwiększa złożoność zapytań i może wpływać na wydajność.

Jednak korzyści są znaczące: brak redundancji, brak anomalii, czysta struktura, oszczędność miejsca, prostsze operacje DML. Dla systemów z częstymi zapisami (INSERT/UPDATE/DELETE) korzyści przewyższają koszty. Dla systemów z częstymi odczytami (SELECT) koszty mogą przewyższać korzyści.

Rozwiązaniem kompromisowym jest użycie widoków (CREATE VIEW), które opakowują JOIN-y i prezentują dane w formie przypominającej jedną tabelę. Aplikacja korzysta z widoku jak z tabeli, a pod spodem dane są przechowywane w 4NF. To łączy zalety normalizacji z wygodą programistyczną.

57/604NF w kontekście całej normalizacji – mapa

Od 1NF do 5NF – gdzie jesteśmy?

  • 1NF: atomowość (Codd 1970)
  • 2NF: częściowe zależności (Codd 1971)
  • 3NF: przechodnie zależności (Codd 1971)
  • BCNF: nakładające się klucze (Boyce, Codd 1974)
  • 4NF: wielowartościowe zależności (Fagin 1977) – TU JESTEŚMY
  • 5NF: złączeniowe zależności (Fagin 1979)
4NF to krok 5 z 6. Za nami: 1NF, 2NF, 3NF, BCNF. Przed nami: 5NF.
Mapa normalizacji – schody od 1NF do 5NF

Mapa normalizacji od 1NF do 5NF pokazuje, że 4NF jest przedostatnim krokiem. Za nami: 1NF (atomowość, 1970), 2NF (częściowe zależności, 1971), 3NF (przechodnie zależności, 1971), BCNF (nakładające się klucze, 1974). Przed nami: 5NF (złączeniowe zależności, 1979).

Każdy krok normalizacji eliminuje konkretny typ problemu. 4NF eliminuje problemy związane z MVD, czyli niezależnymi listami wartości. To ważny krok, bo MVD są częstsze niż się wydaje – występują wszędzie tam, gdzie jeden obiekt ma wiele wartości tego samego typu.

Po 4NF pozostaje jeszcze jeden krok – 5NF, która eliminuje zależności złączeniowe (JD). JD są jednak bardzo rzadkie w praktyce – większość baz danych nigdy ich nie napotyka. Dlatego 4NF jest często uznawana za praktyczne maksimum normalizacji dla większości systemów.

58/60Przygotowanie do 5NF – co nas czeka?

Ostatni krok normalizacji

  • Po 4NF wciąż mogą istnieć zależności złączeniowe (JD)
  • 5NF: eliminacja zależności złączeniowych
  • 5NF wymaga rozkładu na tabele binarne
5NF to najwyższa postać normalna w modelu relacyjnym.
Schemat: trójskładnikowa relacja rozkładana na tabele binarne

Przygotowanie do 5NF: po 4NF wciąż mogą istnieć zależności złączeniowe (JD), które nie są wykrywane przez 4NF. JD to uogólnienie MVD na więcej niż dwa zbiory atrybutów. Podczas gdy MVD dotyczy dwóch niezależnych list, JD dotyczy trzech lub więcej. 5NF eliminuje JD, rozkładając tabelę na tabele binarne.

W naszym przykładzie bibliotecznym, potencjalna JD może wystąpić w relacji trójskładnikowej (np. ISBN, Autor, Bibliotekarz). Jeśli wszystkie pary tych atrybutów są niezależne, to JD może być spełniona, a tabela nie jest w 5NF. Wtedy trzeba rozłożyć na trzy tabele binarne.

Na szczęście JD są bardzo rzadkie w praktyce. Większość systemów zatrzymuje się na 3NF lub BCNF, a 4NF jest stosowana wybiórczo. 5NF to głównie wiedza akademicka – warto ją znać, ale rzadko stosować. Niemniej, pełne zrozumienie normalizacji wymaga znajomości wszystkich postaci normalnych.

59/60FAQ – często zadawane pytania o 4NF

Odpowiedzi na najczęstsze pytania

  • P: Czy 4NF wymaga BCNF? TAK
  • P: Czy każda tabela w BCNF jest w 4NF? NIE
  • P: Jak często naruszenia 4NF? Rzadko – ~1% baz
  • P: Czy 4NF jest ważniejsza od 3NF? NIE
  • P: Czy mogę pominąć 4NF? TAK
Najważniejsze pytanie: 'Czy naprawdę potrzebuję 4NF?'
FAQ – lista pytań i odpowiedzi

FAQ: Czy 4NF wymaga BCNF? Tak, 4NF = BCNF + warunek na MVD. Bez BCNF nie ma 4NF. Czy każda tabela w BCNF jest w 4NF? Nie – tabela może być w BCNF, ale naruszać 4NF (jak nasza tabela DaneKontaktowe). BCNF to warunek konieczny, ale nie wystarczający dla 4NF.

Jak często występują naruszenia 4NF? Rzadko – szacuje się, że około 1% baz danych wymaga 4NF. Większość systemów nie ma niezależnych list wartości, więc 4NF jest spełniona automatycznie. Czy 4NF jest ważniejsza od 3NF? Nie – każda postać normalna jest ważna w swoim kontekście. 3NF jest fundamentalna, 4NF jest uzupełnieniem.

Czy mogę pominąć 4NF? Tak, możesz. Wiele systemów produkcyjnych działa w 3NF lub BCNF i nigdy nie napotyka problemów związanych z MVD. Decyzja o normalizacji do 4NF zależy od konkretnych danych i wymagań biznesowych. Jeśli nie masz MVD – nie potrzebujesz 4NF.

60/60Dziękuję / Zapowiedź 5NF

Podsumowanie i co dalej?

Gratulacje! Poznałeś czwartą postać normalną (4NF).

Kluczowa myśl: każda postać normalna eliminuje konkretny typ problemu.

  • 1NF ✔ 2NF ✔ 3NF ✔ BCNF ✔ 4NF ✔
  • 5NF: eliminacja zależności złączeniowych – ostatni krok

Zapowiedź: '5NF: Piąta postać normalna – zależności złączeniowe'

4NF to przedostatni krok normalizacji. 5NF zamyka temat.
Metafora drogi: 'Jesteś tutaj' na etapie 4NF, przed nami 5NF

Gratulacje! Poznałeś czwartą postać normalną. Kluczowa myśl: każda postać normalna eliminuje konkretny typ problemu. 1NF eliminuje nieatomowe wartości, 2NF – zależności częściowe, 3NF – przechodnie, BCNF – nakładające się klucze FD, 4NF – zależności wielowartościowe. Przed nami 5NF – zależności złączeniowe.

W trakcie tej prezentacji przeszliśmy od teorii (definicja MVD) przez przykłady (system biblioteczny) do praktyki (implementacja w MariaDB). Mamy nadzieję, że to kompleksowe podejście pomogło Ci zrozumieć nie tylko co to jest 4NF, ale przede wszystkim kiedy i jak ją stosować.

Normalizacja to potężne narzędzie w rękach projektanta baz danych. Pozwala tworzyć struktury danych, które są czyste, wydajne i odporne na anomalie. 4NF to kolejny krok w tej podróży – od atomowości (1NF) po niezależność list (4NF). Powodzenia w dalszej nauce!