Planowanie bazy danych MySQL dla aplikacji webowych
Gdy trzech pracowników księguje towar równolegle rano, klient sprawdza status dostawy, a back office tworzy fakturę, jakość aplikacji nie objawia się w jej designie. Pokazuje się w tym, czy wszyscy widzą dokładnie ten sam, poprawny stan danych. Planowanie bazy danych MySQL dla aplikacji webowej nie oznacza więc tworzenia tabel tak szybko, jak to możliwe. Oznacza zrozumienie rzeczywistych przepływów pracy na tyle precyzyjnie, aby zapewnić, że dane pozostają niezawodne nawet pod obciążeniem, podczas błędów, i w miarę wzrostu firmy.
Szczególnie w platformach wewnętrznych, procesach magazynowych i zamówień, lub portalach klienckich, baza danych jest często traktowana zbyt późno. Najpierw buduje się interfejs, potem dodaje się pola, następnie wyjątki. To działa dla prototypu. W działalności operacyjnej skutkuje to zduplikowanymi zbiorami danych, niejasnymi stanami, i raportami, którym nikt już w pełni nie ufa.
Planowanie bazy danych MySQL dla aplikacji webowych: zacznij od przepływu pracy
Pierwszy szkic nie powinien zaczynać się od nazw kolumn, lecz od konkretnej sytuacji roboczej. Weźmy przyjęcie towaru: dostawa przybywa, jest przypisywana do dostawcy i zamówienia, ilości są sprawdzane, przydzielana jest lokalizacja magazynowa, i zapas się zmienia. W zależności od działalności, proces ten dodatkowo wymaga zdjęć, kontroli jakości, statusu wstrzymania, lub możliwej do prześledzenia korekty.
Z tego przepływu pracy wyłaniają się obiekty funkcjonalne. Typowymi przykładami są artykuły, dostawcy, zamówienia, pozycje, lokalizacje magazynowe, ruchy zapasu, i użytkownicy.
Rozróżnienie między obiektem a zdarzeniem jest kluczowe. Artykuł opisuje, czym coś jest. Ruch zapasu dokumentuje, że ilość zmieniła się w konkretnej lokalizacji w konkretnym momencie. Mieszanie obu w jednej tabeli szybko prowadzi do utraty możliwości prześledzenia.
Kilka trudnych pytań pomaga dla każdego obiektu: jaka jest unikalna tożsamość? Która informacja może się zmieniać? Kto może ją zmieniać? Które dane muszą być zachowane historycznie? I jakie reguły obowiązują, gdy dwie osoby pracują jednocześnie? Te pytania zapobiegają późniejszej improwizacji lepiej niż długa lista rzekomo kompletnych pól bazy danych.
Model danych powinien wyrażać reguły
Baza danych to nie tylko magazyn dla danych wejściowych formularza. Powinna sama wymuszać centralne reguły. Jeśli każdy ruch zapasu musi należeć do dokładnie jednego artykułu i jednej lokalizacji magazynowej, klucze obce należą do modelu. Jeśli zewnętrzny numer zamówienia może wystąpić tylko raz na najemcę, wymagany jest unikalny indeks. Jeśli pozycja nigdy nie powinna istnieć bez zamówienia nagłówkowego, ta relacja musi być jasno zamodelowana.
MySQL 8 z InnoDB zapewnia dla tego solidne fundamenty: transakcje, klucze obce, mechanizmy blokowania, i spójne zmiany w wielu tabelach. Podczas zapisywania ruchu, aktualnego zapasu, i dziennika kontroli podczas księgowania przyjęcia towaru, powinno się to odbywać jako spójna transakcja. Jeśli jeden krok zawiedzie, żadna niedokończona operacja nie może pozostać.
Jednak nie każda reguła należy do bazy danych. Zatwierdzenia, złożona logika cenowa, lub kroki procesu zależne od roli są często lepiej umieszczone w logice aplikacji, ponieważ zmieniają się funkcjonalnie szybciej. Granica jest pragmatyczna: reguły, których naruszenie trwale uszkadza dane, powinny być zabezpieczone jak najbliżej danych. Reguły, które zmieniają się często lub mocno zależą od kontekstu, wymagają dobrze przetestowanego kodu aplikacji.
Nie myl historii z aktualnymi wartościami
Częstym błędem jest przechowywanie tylko aktualnego zapasu lub aktualnego statusu. To wystarcza, dopóki ktoś nie zapyta, dlaczego ilość zmieniła się wczoraj lub kto zresetował zamówienie. Dla systemów operacyjnych, historia ruchów lub zdarzeń jest często bardziej wartościowa niż pojedyncze pole do nadpisania.
To nie oznacza trwałego rejestrowania każdego ruchu kliknięcia. Powinny być rejestrowane zmiany istotne biznesowo: zmiany statusu, modyfikacje ilości, korekty, zatwierdzenia, i przypisania. Dobry wpis audytowy zawiera znacznik czasu, użytkownika lub proces systemowy, poprzednią i nową wartość, i zrozumiały powód, gdy wymaga tego przepływ pracy. To umożliwia wyjaśnianie błędów bez konieczności przeszukiwania e-maili, list papierowych, lub kopii zapasowych bazy danych.
Świadomie wybieraj klucze, typy danych, i konwencje nazewnictwa
Decyzje techniczne wydają się małe, ale kształtują utrzymanie i integracje przez lata. Dla wewnętrznych kluczy głównych, wartości BIGINT z automatycznym przydzielaniem są często trzeźwym, łatwym do zarządzania wyborem. UUID mogą być sensowne, gdy dane pochodzą offline, wiele systemów zapisuje niezależnie, lub zewnętrzne interfejsy nie powinny ujawniać sekwencyjnych ID. Jednak kosztują więcej miejsca i wymagają nieco więcej uwagi przy indeksach i sortowaniu.
Kwoty pieniężne powinny być przechowywane jako DECIMAL, nie FLOAT lub DOUBLE. Ilości również potrzebują funkcjonalnie odpowiedniej precyzji: liczby sztuk są często liczbami całkowitymi, podczas gdy wagi i długości nie. Znaczniki czasu powinny być traktowane jednolicie, najlepiej wewnętrznie w UTC, podczas gdy interfejs wyświetla lokalną strefę czasową działalności. Szczególnie podczas zmian zmianowych i czasu letniego, to zapobiega trudnym do znalezienia rozbieżnościom.
Nazwy powinny być też nudne i jednoznaczne. order_items lub inventory_movements są bardziej pomocne niż kreatywne skróty, które rozumie tylko oryginalny zespół projektowy. Spójne formy liczby pojedynczej lub mnogiej są mniej ważne niż spójność. Równie sensowne są pola takie jak created_at, updated_at, i, gdy potrzeba, deleted_at. Miękkie usuwanie nie jest jednak standardowym obowiązkiem. Dla prawnie lub operacyjnie istotnych rekordów, czyste anulowanie jest zwykle lepsze niż niewidocznie usunięty zbiór danych.
Indeksy podążają za rzeczywistymi zapytaniami, nie za zgadywaniem
Indeks może masowo przyspieszyć wyszukiwanie, ale czyni operacje zapisu bardziej złożonymi i zużywa miejsce. Dlatego „indeks na każdym polu" nie jest strategią. Najważniejsze zapytania powinny być ustalone wcześnie: otwarte zamówienia klienta, ruchy artykułu w danym okresie, zapas na lokalizację magazynową, lub ostatnio zmodyfikowane rekordy dla interfejsu.
Kolejność indeksów złożonych ma tu znaczenie. Jeśli aplikacja regularnie wyszukuje według tenant_id, status, i created_at, indeks złożony w dokładnie tej kolejności jest często sensowny. Czy faktycznie pasuje, pokazuje plan wykonania za pomocą EXPLAIN, nie przeczucie. Bazy danych nie są czynione szybkimi przez spektakularne sztuczki, lecz przez obserwowalne zapytania, pasujące indeksy, i realistycznie przetestowane wolumeny danych.
Dla rosnących tabel, jasna strategia przechowywania jest warta uwagi. Czy dzienniki techniczne muszą siedzieć w podstawowej bazie danych produkcyjnej przez pięć lat? Niekoniecznie. Rekordy biznesowe, ruchy, i dowody kontroli wymagają innych okresów przechowywania niż informacje debugowania. Archiwizacja nie jest oznaką słabego systemu, lecz przemyślaną decyzją operacyjną.
Działalność wielu użytkowników wymaga transakcji i jasnych stanów
W aplikacji webowej wiele żądań uzyskuje dostęp do tych samych danych jednocześnie. To normalne w codziennej działalności magazynowej, nie wyjątek. Dwóch pracowników może księgować ten sam zapas, podczas gdy import tworzy nowe zamówienia. Bez transakcji i ukierunkowanego blokowania, istnieje ryzyko utraconych modyfikacji lub ujemnych zapasów, które stają się widoczne dopiero tygodnie później.
Dla operacji krytycznych, powinno być jasne, jakie dane są odczytywane i zapisywane w ramach transakcji. Czasami wystarczy atomowa aktualizacja, taka jak zapas, który jest zmieniany tylko wtedy, gdy dostępna ilość jest wystarczająca. W innych przypadkach blokada wiersza jest sensowna, aby operacja mogła sprawdzić stan danych w kontrolowany sposób i zmodyfikować go potem. Długie transakcje, z drugiej strony, są problematyczne: blokują inną pracę i zwiększają ryzyko konfliktów.
Równie ważny jest ograniczony zestaw stanów funkcjonalnych. Zamówienie nie powinno być jednocześnie „otwarte", „częściowo dostarczone", i „ręcznie przetworzone" z powodu utrzymywanych sprzecznych pól. Zdefiniowane przejścia statusu czynią interfejsy, raporty, i automatyzacje prostszymi. Wyjątki mogą być dozwolone, ale powinny być nazwane i udokumentowane.
Zaplanuj bezpieczeństwo, najemców, i działalność od początku
Aplikacja powinna używać dedykowanego użytkownika bazy danych dla MySQL z minimalnymi uprawnieniami. Dostęp do zapisu dla aplikacji webowej nie oznacza, że ten użytkownik potrzebuje usuwać tabele lub zmieniać uprawnienia użytkowników. Konta administracyjne nie należą do plików konfiguracyjnych produkcji i nigdy do repozytorium.
Gdy wielu klientów, lokalizacji, lub firm pracuje w ramach aplikacji, izolacja najemców jest decyzją architektoniczną, nie retroaktywnym warunkiem filtrowania. Wspólna baza danych z tenant_id może być wydajna i łatwa do utrzymania, ale wymaga spójnych kontroli w każdym zapytaniu i jasnych reguł dla indeksów. Oddzielne bazy danych oferują silniejszą izolację, jednak zwiększają wysiłek w aktualizacjach, ewaluacjach, i działalności. Który wariant pasuje, zależy od wymagań ochrony danych, wolumenu danych, i modelu biznesowego.
Kopie zapasowe są kopiami zapasowymi dopiero wtedy, gdy przywrócenie zostało przetestowane. Wymagany jest zdefiniowany rytm dla kopii zapasowych, przechowywania, i odzyskiwania. Podobnie, monitorowanie miejsca na dysku, wolnych zapytań, i nieudanych zadań, wraz z udokumentowanymi aktualizacjami, należą do systemu. MySQL 8, PHP 8.4, i nowoczesne aplikacje webowe mogą być dobrze obsługiwane długoterminowo, jeśli zależności, dane dostępowe, i kroki wdrożenia nie znajdują się wyłącznie w głowie dewelopera.
Sensowny plan przed pierwszym dniem w produkcji
Przed wdrożeniem powinien istnieć zwarty model danych z przykładowymi przepływami pracy. Obejmuje to kluczowe tabele i relacje, reguły statusu, uprawnienia, oczekiwane zapytania, interfejsy, i koncepcję dla kopii zapasowych i dzienników audytowych. Ten plan nie musi mieć stu stron. Musi uchwycić decyzje, których poprawienie później byłoby kosztowne.
W softify.pro, planowanie bazy danych zaczyna się więc od ludzi, którzy księgują, sprawdzają, kompletują, lub rozwiązują wyjątki. Jeśli istniejący arkusz kalkulacyjny niezawodnie odwzorowuje możliwy do opanowania proces, może pozostać poprawnym rozwiązaniem. Jeśli wiele osób pracuje jednocześnie, powstają rekordy, i błędy muszą być możliwe do prześledzenia, baza danych z kolei zasługuje na taki sam wysiłek planistyczny jak interfejs. Najlepsza architektura w końcu to ta, która upraszcza dzień pracy i nadal może być zmieniona przejrzyście za dwa lata.