Denormalizacja to celowe złamanie reguły normalizacji. Denormalziacja za pomocą celowej redundancji danych, kosztem wielkości bazy danych i zwiększonego ryzyka związanego z możliwością utraty jej spójności może przyspieszyć zwracanie odpowiedzi kilkaset razy szybciej a w skrajnych przypadkach o więcej rzędów wielkości szybciej.
Aby zrozumieć czym jest denormalizacja najpierw musimy zrozumieć:
- czym jest normalizacja,
- jaki wpływ na wydajność mają złączenia tabel (JOIN),
- czym jest złożoność obliczeniowa.
Normalizacja – krótkie i ogólne przypomnienie
Normalizacja baz danych polega na tym aby pozbyć się wszelkiej redundancji w bazie danych. Przykładowo, bazę danych każdego sklepu internetowego można byłoby sprowadzić do jednej tabeli, która zawierała by wszystko dane o zamówieniach:

Jak wiadomo w takim przypadku nie wykorzystujemy istoty relacyjnych baz danych. Łatwo o pomyłki, trudno ją przetwarzać w back-endzie, baza taka będzie się szybko rozrastać, ponieważ nie potrzebnie powiela dane o klientach itd. itp. Normalizacja to dekompozycja takiej tabeli na wiele mniejszych, które następnie możemy połączyć za pomocą kluczy:

Oczywiście, to bardzo uproszczony i spłycony przykład – chodzi o samą istotę. Czytaj więcej o trzech postaciach normalnych a nawet 3.5, 4 i 5: https://pl.wikipedia.org/wiki/Posta%C4%87_normalna_(bazy_danych)
Wpływ normalizacji na objętość i wydajność baz danych
Takie działanie, które polegało na wyciągnięciu szczegółów dotyczących klientów do osobnej tabeli wiąże się z wieloma korzyściami:
- baza danych zajmuje mniej fizycznego miejsca na dysku (szczegóły dotyczące jednego klienta nie są kopiowane przy kolejnych zakupach),
- możliwe jest łatwe przetwarzanie danych (można łatwo wybrać wszystkie zamówienia posługując się kluczem ID klienta),
- większa spójność danych (wiadomo że Jan Kowalski to ten sam Jan Kowalski bez sprawdzania adresu, edycja jego szczegółów będzie widoczna w zapytaniach dotyczących wszystkich innych jego zakupów)
Wady normalizacji polegają na tym że:
- silnik musi łączyć te tabele, (jest to operacja a więc dodatkowa praca, która musi być wykonana podczas zapytania SELECT zawierających JOIN).
Łączenie dwóch tabel w celu wybrania konkretnych danych i wybór danych z powstałej w ten sposób tabeli wymaga od procesora i pamięci RAM większego wysiłku niż wyszukiwanie danych w jednej tabeli. Mówi się wtedy, że pierwsze rozwiązanie ma większą złożoność obliczeniową – tak jak w przypadku algorytmów. Niekorzystne konsekwencje złożoności pewnych procesów są widoczne w przypadku większej skali.
Im większe tabele i im bardziej skomplikowane zapytanie, tym wpływ normalizacji na wydajność działania bazy danych i szybkość zwracania odpowiedzi jest coraz gorszy.
Normalizacja baz danych jest jak programowanie orientowane obiektowo – to tylko zasada, której zastosowanie w praktyce ma zarówno swoje zalety i wady. Im bliżej nam do rozwiązań typowo akademickich i czysto naukowych tym bliżej nam do normalizacji a im bliżej praktyki, skalowania i „brudu” hakowania ich wydajności tym bliżej nam do ich łamania.
Zalety denormalizacji baz danych
- radykalny zysk wydajności,
- obniżenie kosztów CPU/RAM,
- odciążenie innych technik optymalizacyjnych (oszczędność cache)
Wady denormalizacji baz danych
- większe ryzyko utraty spójności danych,
- dodatkowa praca w kodzie aplikacji w przypadku inkrementowania/dekrementownaia liczników lub wykonania nowych transkacji,
- może utrudniać rozwój i przebudowę schematów tabel.
Praktyczne przykłady denormalizacji baz danych
Przykład 1: Głosy i rankingi
Załóżmy, że mamy aplikację typu Instagram, w której możemy dodawać polubienia/serduszka etc. Jeżeli chcemy sumę tych polubień pokazywać przy każdym zdjęciu w idealnie znormalizowanej aplikacji będziemy musieli te serduszka uzyskiwać w wyniku zliczania COUNT() w tabeli, która rejestruje polubienia z odpowiednim zdjęciem i id osoby oddającej swój głos.
Biorąc pod uwagę, że wyświetlanie zdjęć prawie zawsze wiąże się ze zliczaniem serduszek opłaca się sumę serduszek zapisywać w nadmiarowej tabeli ze zdjęciami. Nie będziemy musieli łączyć tabel i nie będziemy musieli wykonywać czasochłonnej operacji COUNT. Jeżeli teraz będziemy chcieli zrobić ranking osób, które uzyskały najwięcej polubień, to w znormalizowanej tabeli będziemy musieli wykonać takie zapytanie:
SELECT COUNT(*) FROM likes JOIN photos ON like_targetid = photo_id WHERE photo_userid - 4096;
W zdenormalizowanej tabeli możemy zaś wykonać zwykłe:
SELECT SUM(photo_likecount) FROM photos WHERE photo_userid = 4096;
I teraz ciekawostka drugie zapytanie wykonuje się czterysta razy szybciej przy zaledwie 30 tysiącach zdjęć i paru tysiącach użytkowników.
W zamian musimy: przy każdym polubieniu sprawdzać czy konkretny użytkownik polubił zdjęcie oraz inkrementować licznik jeżeli jeszcze nie polubił i dekrementować jeżeli już polubił (bo to oznacza, że chce cofnąć swojego lajka).
Potencjalna utrata spójności w wyniku denormalziacji może polegać na tym, że powyższe „dodatkowe działania które trzeba wykonać” w związku z inkrementacją i dekrementacją licznika będą wykonanie niedbale lub np. nie będą przewidywać jakichś rzadkich okoliczności np. błędów, przerwania połączenia itd…
Podsumowanie
Denormalizacja to optymalizacja baz danych polegająca na tym, że przechowujemy dodatkowe dane, które moglibyśmy uzyskać poprzez zliczenie innych danych lub złączenie tabel. Wyniki poprawnie przeprowadzonej denormalizacji mogą być spektakularne.
Odpowiedz lub skomentuj