Dlaczego zmieniłem zdanie o nierelacyjnych bazach danych
Ostatnimi czasy zrobiło się głośno na temat nierelacyjnych baz danych. Wywodzę się ze starego modelu, gdzie sql i relacje to podstawy myślenia o strukturze danych. Zawsze kiedy rozpoczynam nowy projekt, zastanawiam się nad strukturą danych w bazie szukając powiązań pomiędzy nimi. Gdy po raz pierwszy zderzyłem się z modelem nierelacyjnym, stwierdziłem: to bez sensu, nie da się na tym pracować. Zobacz, dlaczego zmieniłem zdanie.
Mariusz Walczak. Tech lead w Softfin. Absolwent Warszawskiej Wyższej Szkoły Informatycznej. Pasjonat inżynierii oprogramowania, swoje aplikacje tworzy w PHP i językach opartych na ES6/7. Prywatnie miłośnik futrzanych czworonogów, oraz winiarstwa i nalewkarstwa. Wszystkie jego teksty znajdziecie pod tym adresem.
Spis treści
Pewne ustalenia
Umówmy się, że odpowiednia struktura danych to podstawa dobrego systemu komputerowego. Jeżeli słabo ją przygotowaliśmy, to na pewno nic dobrego z tego nie wyjdzie — nawet mając na pokładzie najlepszych programistów. Działa to też w drugą stronę, jeśli mamy perfekcyjnie zrobiony model, ale słabych programistów, to mimo pewnych braków prawdopodobnie stworzą z tego średnią aplikację, a może z czasem poprawią ją na coś lepszego.
Często struktura danych mówi nam co się ma zadziać i kiedy, na podstawie struktury danych często modelujemy systemy administracyjne. Są nawet wzorce, które bazują na modelach, czyli strukturze danych MDA, chociażby.
Relacyjne bazy danych
Nie wchodząc w szczegóły, relacyjne bazy danych, to taki twór, który posiada relacje pomiędzy tabelkami w bazie, gdzie każda z nich przedstawia jakiś obiekt do zapisania. Przykład: mamy aplikacje do wynajmowania mieszkań. Zezwala ona na przypisanie lokatora do mieszkania, czyli mamy listę mieszkań i listę potencjalnych lokatorów. Przypisujemy jednego lokatora do jednego mieszkania, mamy wtedy relacje 1:1 (jeden do jednego). Możemy mieć także sytuacje, kiedy jeden lokator posiada wiele mieszkań — wtedy mamy 1:n (jeden do wielu). Trzecia sytuacja, kiedy wiele mieszkań może mieć wiele lokatorów, wtedy mamy sytuację n:m, czyli wiele do wielu.
Nierelacyjny model bazy danych
W przypadku nierelacyjnego modelu nie ma relacji. Są za to związki, czyli obiekt, który dostajemy może mieć w sobie zapisany obiekt powiązany, ale z tą różnicą, że jeżeli w przypadku relacyjnych chcielibyśmy usunąć obiekt powiązany z głównym, to relacyjna krzyknie błędem, a nierelacyjna “nie odezwie” się.
Oj, czy przez przypadek nie znalazłem pierwszego problemu, czyli braku utrzymania całości logicznej? W relacyjnej bazie danych, jak zmienię markę samochodu z Opel na Hopel, to nie muszę niczego więcej zmieniać. W systemie czysto nierelacyjnym niestety na każdym modelu muszę zmienić nazwę.
Nie mówimy o sytuacjach, gdzie dajemy odsyłacz po ID, dla mnie jest to robienie relacyjnej bazy danych na nierelacyjnym silniku.
Co z transakcjami?
Najprostszy przykład, mamy dostarczyć 10000 elementów do bazy, wrzucamy zapytanie i nagle w połowie urywa nam łącze. W przypadku transakcyjnych systemów, całość zapytań robionych w tej transakcji zostanie odrzucona, w przypadku nietransakcyjnych, tyle ile zapiszę, tyle zostanie zachowane, ale do końca nie będziemy wiedzieli, ile rekordów zostało zapisanych poprawnie.
Systemy nierelacyjne póki co nie wspierają transakcyjności. Czyli kolejny błąd i uchybienie.
Analiza przeciętnego systemu internetowego
Klasyczny system internetowy ma system logowania, na podstawie tego mamy jakieś uprawnienia, dzięki którym możemy coś zrobić, a czegoś nie. Dodatkowo mamy różne poziomy dostępu do systemu. Czyli system relacyjny aż się patrzy. Nawet prosty przykład ze stroną naszej poczty jest idealnym przykładem strony opartej na relacyjnym systemie bazodanowym.
O co to całe halo
Systemy nierelacyjne są o niebo szybsze tam, gdzie systemy relacyjne robią operacje w 10ms, to ta sama operacja w nierelacyjnym systemie będzie kilkaset razy szybsza, plus cache i mamy rakietę. W sumie to tyle pozytywów.
Czyżby?
Z punktu widzenia logiki popełniłem jeden błąd. Wszystkie wspomniane systemy są projektowane pod relacyjne bazy danych. Model nierelacyjny wrócił po dłuższej nieobecności do łask. Jest to zupełnie inne podejście projektowe. Tutaj nie myślimy co z czego ma wynikać, nie tworzymy struktury naczyń połączonych. Wreszcie, nie mamy relacji po stronie baz danych tylko po stronie aplikacji.
Jakiś przykład?
Wymyślmy sobie prosty blog. Mamy głównego użytkownika, który pisze artykuły, mamy też czytelnika, oraz osobę zalogowaną, czyli czytelnika z możliwością komentowania. Teraz tworzymy kolekcje:
- użytkownicy. Zbieramy w niej imię nazwisko, mail, jakiś hash, oraz inne dane o użytkownikach.
- posty. Mamy wszystkie dane o poście oraz sub-obiekt z imieniem, nazwiskiem i z czym tam trzeba autora.
— W obiekcie kolekcji posty, mamy też subobiekt komentarz, który niesie ze sobą takie wiadomości jak tytuł, treść oraz imię i nazwisko autora.
Zauważcie, że nie ma bezpośredniej relacji pomiędzy kolekcjami użytkowników oraz postami. Jak teraz dodać komentarz? Logujemy się, do ciasteczka trafia wtedy jakiś hash mówiący backendowi, że my to my. Backend do każdego żądania dostaje taki hash i na tej podstawie rozróżnia, kto go o co prosi i decyduje co wysyła w odpowiedzi. Frontend dowiaduje się od backendu, jakie podstrony może mu pokazać, a jakie nie.
Oczywiście frontend nie jest zabezpieczeniem, tutaj backend broni danych i mówi co komu wolno. Niemniej, gdy ktoś wypełni formularz komentarza, to backend będzie wiedział, kto to zrobił. Wtedy uzupełni obiekt kolekcji posty o odpowiednie dane.
Co nam to dało?
W relacyjnym systemie zrobilibyśmy to samo, ale bez tych dziwnych zabiegów. Po co to nam? Blogerzy, ile razy zmieniacie swoje posty? Komentujący, ile razy zmieniacie komentarze? No właśnie, relacyjny system broni struktury na wypadek zmian. Natomiast tutaj tych zmian będzie niewiele, co więcej możemy sobie wyszukać po konkretnych osobach wszystko w kolekcji, a wyszukanie w nierelacyjnych systemach jest dużo szybsze. Przepraszam, o wiele szybsze, to jak porównywać wspomnianego Opla z Ferrari.
Także nierelacyjne systemy baz danych poważnie robią robotę. Testowałem je na blogach, systemach sklepów internetowych, na stronach typu wizytówka, na aplikacjach do zarządzania zasobami ludzkimi. Poważnie widzę wielki potencjał, ale ten potencjał wymaga innego myślenia.
Jak więc myśleć?
To jest najpiękniejsze. Skończyły się czasy zadań, bo nie mam użytkownika, więc tego nie zrobię. W systemach nierelacyjnych każdy element kolekcji musi mieć komplet danych w sobie, co znacznie ułatwia mockowanie. Sam pamiętam, jak w jednym systemie, aby móc dodać przykładowe ubezpieczenie, musiałem uzupełnić 43 tabelki. W systemie nierelacyjnym mam strukturę modelu i tam musi być wszystko.
Więc jeżeli robimy system do zarządzania parkingiem, to mamy kolekcje miejsc parkingowych i jak coś tam zaparkuje, to po prostu dopisujemy subobiekt reprezentujący ten pojazd do elementu kolekcji miejsc. Powstaje wtedy ciekawy potworek, ale za to czuć tą różnicę.
Skoro to takie super, to czy wyprze systemy relacyjne?
Zdecydowanie nie. Tak jak wspomniałem, systemy nierelacyjne nie pilnują struktury danych, to robi aplikacja. W systemach relacyjnych nie usuniemy powiązanej danej ot tak. System wymusi na nas decyzję świadomą, dodatkowo systemy relacyjne nie dopuszczają do sytuacji, że usuniemy użytkownika i pozostawimy jego powiązane dane w bazie. System transakcyjności jest też bardzo przydatny w szczególności tam, gdzie musimy mieć pewność.
Wyobraźmy sobie system bankowy oparty na nierelacyjnym systemie baz danych. Idziemy do bankomatu, pobieramy pieniądze, dajmy na to 10 zł. System sprawdza, czy na koncie mamy takie środki, potwierdza. Pobiera nam je z konta, wysyła potwierdzenie wypłaty i w tym momencie pada łącze. Oficjalnie dostaliśmy pieniądze, ale fizycznie ich nie mamy.
Innym przykładem może być usunięcie naszego konta. Usuwamy konto, więc znikają nasze dane, ale ktoś zapomniał podpiąć pod ten proces historię kredytową, która nie jest zbyt korzystna. Pozostała w tym banku, pomimo tego, że kazaliśmy wszystko usunąć. Powiecie, że bank robi archiwa i przyznam Wam rację. Dane te nie są jednak brane do statystyk, podliczeń, czy raportów. Potem dowiemy się, że nasz poprzedni bank ma ponad 20 mln klientów, z czego 5 mln nie do końca usunięci klienci.
Gdzie używać nierelacyjnych baz danych
Wszędzie tam, gdzie wiemy, że aplikacje nie muszą posiadać specjalnych zabezpieczeń pilnujących spójności tych danych. Czyli ogólnie 95% naszych stron internetowych. Bałbym się używać systemów nierelacyjnych do operacji pieniężnych. Łatwo można coś przeoczyć, albo źle zarchiwizować, a potem trafi się klient cwaniaczek i będzie chciał odszkodowanie .
Bałbym się też systemów, w których są dane bardzo poufne i ważne, np. systemy medyczne. Tutaj wydaje mi się, że sztywna struktura danych jest bardzo ważna, podobnie jak w administracji publicznej. Stronki promocyjne, jak konkursowe, lub małe CMS to idealne pole do popisu dla nierelacyjnych baz danych.
Zdjęcie główne artykułu pochodzi z pexels.com.