Streszczenie
  • Czym jest normalizacja
  • Kluczowe założenia normalizacji
  • Postacie normalne (normal forms)
  • Pierwsza postać normalna (1NF)
Normalizacja baz danych

Projektując bazę danych łatwo wpaść w pułapkę duplikowania pól, powtarzania nazw klientów w wielu miejscach czy mieszania kilku typów informacji w jednej tabeli. Normalizacja to proces, który temu zapobiega — porządkuje dane, rozbija je logicznie na tabele i zapewnia, że każda informacja ma jedno źródło prawdy.

Newsletter · co środę

Zostań lepszym w SQL — bez nudy

Zapisz się na newsletter i otrzymaj praktyczne ćwiczenia SQL, wskazówki do rozmów rekrutacyjnych i skrót do kursu SkumajBazy.

2 312 czytelników · ⭐ 4,8

W tym artykule zobaczysz, jak działają kolejne postacie normalne (1NF, 2NF, 3NF), dlaczego są ważne i jak uniknąć typowych anomalii przy aktualizacjach czy złączeniach danych. To nie sucha teoria — przejdziemy przez konkretne przykłady tabel, które najpierw łamią zasady normalizacji, a potem zostają poprawione krok po kroku.

Czym jest normalizacja

Normalizacja baz danych to systematyczne projektowanie schematu bazy tak, aby ograniczyć redundancję danych i zminimalizować ryzyko anomalii aktualizacji, wstawiania i usuwania. Oparta jest na zależnościach funkcjonalnych między atrybutami oraz na precyzyjnie zdefiniowanych kluczach. Celem jest spójność i jednoznaczność przechowywanych informacji.

W praktyce normalizacja porządkuje dane w tabele według tematów, a powiązania realizuje przez klucze obce zamiast duplikowania pól w wielu miejscach. Dzięki temu jedna zmiana trafia w jedno źródło prawdy, co upraszcza utrzymanie. Jeśli dopiero zaczynasz pracę z relacjami i złączeniami, przejrzyj wprowadzenie: Podstawy SQL: SELECT, WHERE, JOIN, GROUP BY.

Kluczowe założenia normalizacji

  • Atrybuty są atomowe i opisują dokładnie jeden fakt. Brak grup powtarzalnych i brak pól-CSV. Identyfikacja wierszy odbywa się przez stabilny klucz główny.
  • Projektowanie schematu bazy danych opiera się na zależnościach funkcjonalnych: jeśli X wyznacza Y, to Y nie powinno pojawiać się w tabeli, w której X nie jest kluczem (chyba że to bezpośrednio wymagane i kontrolowane).
  • Eliminujemy źródła anomalii: brak zależności częściowych od klucza złożonego oraz brak zależności przechodnich między atrybutami niekluczowymi. Dzięki temu zmiany są lokalne, a spójność weryfikowalna.

Postacie normalne (normal forms)

Postacie normalne to kolejne poziomy rygoru. W zastosowaniach OLTP najczęściej dążymy do 3NF. Dalsze formy są potrzebne rzadziej, np. przy złożonych zależnościach wielowartościowych.

Pierwsza postać normalna (1NF)

Pierwsza postać normalna wymaga, aby każda kolumna miała wartości atomowe, bez list i powtórzeń, a wiersze były identyfikowalne przez klucz. Niedozwolone są kolumny typu Telefon1, Telefon2, Telefon3 oraz pola przechowujące listy identyfikatorów rozdzielone przecinkami.

Przykład naruszenia 1NF: tabela Zamówienia z kolumną Produkty='12,15,18' i Ilości='1,2,1'. Poprawka do 1NF to wydzielenie pozycji zamówień do osobnej tabeli, gdzie każdy produkt w zamówieniu jest osobnym wierszem. Dane stają się jednoznaczne i gotowe do złączeń.

Druga postać normalna (2NF)

Druga postać normalna dotyczy tabel z kluczem złożonym. Wymaga 1NF oraz braku zależności częściowych, czyli żaden atrybut niekluczowy nie może zależeć tylko od fragmentu klucza złożonego.

Przykład: w tabeli PozycjeZamówienia(zamówienie_id, produkt_id, ilość, nazwa_produktu) atrybut nazwa_produktu zależy tylko od produkt_id, a nie od całego klucza (zamówienie_id, produkt_id). Poprawka: przenieść nazwę produktu do tabeli Produkty i w PozycjeZamówienia trzymać wyłącznie klucze i atrybuty specyficzne dla pozycji (np. ilość, cena w momencie zakupu).

Trzecia postać normalna (3NF)

Trzecia postać normalna wymaga 2NF oraz braku zależności przechodnich między atrybutami niekluczowymi. Atrybut niekluczowy nie może wyznaczać innego atrybutu niekluczowego.

Przykład: Klienci(klient_id, kod_pocztowy, miasto). Jeśli kod_pocztowy wyznacza miasto, to miasto zależy przechodnio od klient_id przez kod_pocztowy. Poprawka: albo przechowuj tylko kod i dołączaj słownik Kod->Miasto, albo utrzymuj redundancję kontrolowaną z regułami spójności (świadoma denormalizacja, gdy jest ku temu powód).

(Opcjonalnie) Czwarta i piąta postać normalna

Czwarta postać normalna eliminuje zależności wielowartościowe (niezależne listy faktów w jednej tabeli). Piąta dotyczy zależności złączeniowych i minimalizacji utraty informacji przy dekompozycji.

W praktyce OLTP 4NF/5NF pojawiają się rzadko i głównie w złożonych modelach referencyjnych lub integracjach danych. Gdy wzorzec danych sugeruje niezależne wielozbiory w jednej tabeli, rozbij je na oddzielne relacje.

Zalety normalizacji

Normalizacja baz danych redukuje redundancję danych i eliminuje klasyczne anomalia aktualizacji. Aktualizacja informacji w jednym miejscu automatycznie propaguje się poprzez złączenia i klucze obce.

Lepsza spójność przekłada się na prostsze reguły walidacji, mniej wyzwalaczy i mniej kodu naprawczego. 1NF, 2NF, 3NF zwiększają czytelność warstwy danych i ułatwiają refaktoryzacje oraz migracje.

Wady nadmiernej normalizacji

Nadmierna liczba tabel i złączeń może obniżać wydajność zapytań oraz komplikować indeksowanie. Pojawia się większe zapotrzebowanie na JOIN i potencjalnie więcej losowych odczytów.

Aby zrównoważyć koszty, stosuj przemyślaną denormalizację oraz właściwe indeksy pokrywające klucze i predykaty. W praktyce często pomaga staranne projektowanie indeksów: Indeksy w SQL: teoria i praktyka.

Przykład praktyczny

Załóżmy nienormalizowaną tabelę Zamówienia(zamówienie_id, data, klient_nazwa, klient_email, produkty_csv, ilosci_csv). Mamy redundancję danych klienta i problem z atomowością pozycji. Po normalizacji tworzymy tabele: Klienci, Produkty, Zamówienia, PozycjeZamówienia. Redukujemy redundancję i upraszczamy walidację.

Poniżej minimalny schemat i przykładowe zapytanie. Cena w pozycjach jest ceną z chwili zakupu (historyczność bez anomalii).

SQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 -- Schemat 3NF CREATE TABLE klienci ( klient_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, nazwa VARCHAR(200) NOT NULL, email VARCHAR(200) NOT NULL UNIQUE ); CREATE TABLE produkty ( produkt_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, nazwa VARCHAR(200) NOT NULL, cena DECIMAL(10,2) NOT NULL ); CREATE TABLE zamowienia ( zamowienie_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, klient_id INT NOT NULL, data DATE NOT NULL, FOREIGN KEY (klient_id) REFERENCES klienci(klient_id) ); CREATE TABLE pozycje_zamowienia ( zamowienie_id INT NOT NULL, produkt_id INT NOT NULL, ilosc INT NOT NULL, cena DECIMAL(10,2) NOT NULL, -- cena w momencie zakupu PRIMARY KEY (zamowienie_id, produkt_id), FOREIGN KEY (zamowienie_id) REFERENCES zamowienia(zamowienie_id), FOREIGN KEY (produkt_id) REFERENCES produkty(produkt_id) ); -- Dane przykładowe INSERT INTO klienci (nazwa, email) VALUES ('ACME Sp. z o.o.', 'kontakt@acme.example'); INSERT INTO produkty (nazwa, cena) VALUES ('Klawiatura', 100.00), ('Mysz', 50.00); INSERT INTO zamowienia (klient_id, data) VALUES (1, DATE '2025-10-01'); INSERT INTO pozycje_zamowienia (zamowienie_id, produkt_id, ilosc, cena) VALUES (1, 1, 2, 100.00), -- 2x Klawiatura (1, 2, 1, 50.00); -- 1x Mysz -- Suma zamówienia SELECT z.zamowienie_id, k.nazwa AS klient, SUM(pz.ilosc * pz.cena) AS wartosc_brutto FROM zamowienia z JOIN klienci k ON k.klient_id = z.klient_id JOIN pozycje_zamowienia pz ON pz.zamowienie_id = z.zamowienie_id GROUP BY z.zamowienie_id, k.nazwa;

Po normalizacji raporty są prostsze do pisania jako zapytania i widoki. Do składania złożonych agregacji pomocne bywają CTE: Podzapytania i CTE w SQL.

Podsumowanie

Normalizacja baz danych do 3NF powinna być stanem domyślnym dla systemów OLTP. Daje spójność, ogranicza redundancję danych i eliminuje anomalia aktualizacji. Wymusza również klarowne klucze i jawne zależności funkcjonalne.

Denormalizacja jest uzasadniona, gdy mierzalnie poprawia wydajność lub upraszcza krytyczne zapytania. Wprowadzaj ją punktowo, z testami regresji i monitoringiem planów wykonania: Optymalizacja zapytań SQL i analiza planów wykonania.

Kurs · 24 lekcje8h 14m
Kurs

Kurs SkumajBazy — Czas w końcu nauczyć się SQLa

Kompleksowy kurs SQL dla programistów, analityków i wszystkich, którzy chcą efektywnie pracować z danymi. Od podstaw do zaawansowanych zapytań.

  • 24 lekcje wideo + 80 ćwiczeń
  • Realne bazy z e-commerce
  • Społeczność i code-review
499 zł799 zł−38%
Zapisz się na kurs
Część 12 z 27

Optymalizacja zapytań SQL i analiza planów wykonania

druga lekcja cyklu „SQL — naucz się języka zapytań krok po kroku"

Czytaj kolejny →