Dizajn baze podataka: Oblikovanje okosnice za uistinu inteligentne sustave
Inteligentni sustavi ne počinju modelom, nadzornom pločom ni impresivnim API odgovorom. Počinju podacima koji svakom drugom sloju daju nešto pouzdano o čemu može zaključivati. Ako su ti podaci dvosmisleni, duplicirani, loše povezani ili ih je nemoguće sigurno razvijati, inteligencija izgrađena na njima s vremenom će postati skupo nagađanje.
Dizajn baze podataka stoga nije pitanje pohrane koje se prepušta završnoj fazi implementacije. On je okosnica ponašanja sustava. Određuje što aplikacija može znati, s kolikom sigurnošću to može znati i koliko se sigurno može mijenjati kako se mijenja poslovanje.
Modelirajte domenu, a ne prvi zaslon
Česta pogreška u dizajnu jest dopustiti da prvo korisničko sučelje diktira shemu. Obrazac sadrži ime kupca, adresu i popis narudžbi, pa se jedna široka tablica čini praktičnom. Ta praktičnost nestaje kada kupci imaju više adresa, narudžbama treba povijest statusa ili više servisa mora referencirati istog kupca.
Umjesto toga, počnite s trajnim konceptima i odnosima domene. Zapitajte se što mora ostati istinito bez obzira na to kako su organizirani trenutačni API, administrativna ploča ili mobilna aplikacija. U sustavu narudžbi kupci, narudžbe, stavke narudžbe, proizvodi, plaćanja i isporuke zasebni su koncepti jer se mijenjaju neovisno i imaju različita pravila.
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
customer_id BIGINT NOT NULL,
status VARCHAR(30) NOT NULL,
created_at TIMESTAMP NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(id)
);
CREATE TABLE order_items (
id BIGINT PRIMARY KEY,
order_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
quantity INTEGER NOT NULL,
unit_price DECIMAL(12, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
Ova struktura prenosi više od same pohrane. Jasno ističe važnu granicu: stavka narudžbe bilježi cijenu u trenutku kupnje, umjesto da ovisi o trenutačnoj cijeni proizvoda. Ta mala odluka štiti račune, izvještavanje, povrate novca i mogućnost revizije.
Postavite invarijante tamo gdje se ne mogu zanemariti
Validacija u aplikaciji ključna je, ali nije jedino mjesto za kritična poslovna pravila. Pozadinski radnici, skripte za uvoz, poslovi održavanja, budući servisi i ručne operacije mogu zaobići određeni PHP validator zahtjeva. Baza podataka trebala bi provoditi činjenice koje je jedinstveno pozicionirana štititi.
- Koristite primarne ključeve za uspostavljanje stabilnog identiteta.
- Koristite strane ključeve kada odnos mora upućivati na stvarni zapis.
- Koristite
NOT NULLkada odsutnost nema značenje. - Koristite jedinstvena ograničenja za vrijednosti koje se ne smiju ponavljati, poput reference vanjskog pružatelja usluge.
- Koristite ograničenja provjere tamo gdje su podržana i prikladna za jednostavna, trajna pravila.
Ograničenja ne uklanjaju potrebu za jasnim pogreškama aplikacije. Ona pružaju posljednju liniju obrane. U dobro dizajniranom backendu aplikacija rano validira radi dobrog korisničkog iskustva, dok baza podataka konačno validira radi ispravnosti.
Transakcije također pripadaju ovom razgovoru. Naplata plaćanja, rezervacija zaliha i prijelaz stanja narudžbe možda trebaju uspjeti kao jedna cjelina ili ne ostaviti djelomičan rezultat. Definiranje granica transakcija odluka je o dizajnu, a ne naknadna misao koju treba dodati kada kvarovi u produkciji otkriju nedosljedne zapise.
Najprije normalizirajte, denormalizirajte na temelju dokaza
Normalizacija se često opisuje kao akademska vježba, ali njezina je praktična svrha jednostavna: pohraniti činjenicu jednom, na mjestu kojem pripada. Ako se ista adresa e-pošte ili opis proizvoda kopira u mnogo redaka, ažuriranja postaju nepouzdana i nitko ne može biti siguran koja je kopija mjerodavna.
To ne znači da svako čitanje mora rekonstruirati složeni objekt kroz mnoga spajanja. Putanje s mnogo čitanja ponekad imaju koristi od pažljivo odabrane denormalizacije: predmemoriranog agregata, dokumenta za pretraživanje, tablice za izvještavanje ili pohranjene prikazne vrijednosti. Važna je razlika u namjeri. Najprije normalizirajte operativni izvor istine; duplicirane prikaze uvodite samo kada postoji izmjeren razlog, jasan vlasnik i pouzdana strategija ažuriranja.
Na primjer, pohranjivanje order_total može biti razumno kada je izvedeno iz stavki narudžbe i održava se unutar iste transakcije. Pohranjivanje bez definiranog pravila ponovnog izračuna poziva na odstupanja. Izvedeni podaci nisu sami po sebi opasni; neobjašnjeni izvedeni podaci jesu.
Dizajnirajte za upite, indekse i promjene
Shema je uspješna samo ako podržava pitanja na koja sustav mora odgovoriti. Prije dodavanja indeksa utvrdite stvarne obrasce pristupa: pronađite kupca prema adresi e-pošte, navedite nedavne narudžbe kupca, odaberite poslove u redu prema statusu ili dohvatite događaje unutar vremenskog raspona.
Indeks treba služiti upitu, a ne neodređenoj želji da baza podataka bude brža. Svaki indeks dodaje rad pri pisanju i trošak pohrane. Složeni indeksi također imaju posljedice redoslijeda: indeks nad (customer_id, created_at) dobro je prilagođen dohvaćanju nedavnih narudžbi kupca, ali nije jednak indeksu nad (created_at, customer_id).
Koristite planove upita za provjeru pretpostavki u stvarnom sustavu baze podataka i stvarnom obliku skupa podataka. Indeks koji u migraciji izgleda ispravno ipak može ostati neiskorišten zbog neselektivnog uvjeta, izraza oko stupca ili upita koji traži podatke nekompatibilnim redoslijedom.
Neka migracije budu dosadne i povratne po duhu
Produkcijske sheme razvijaju se pod opterećenjem i uz više implementiranih verzija aplikacije. Sigurne migracije uzimaju tu stvarnost u obzir. Dodavanje stupca koji dopušta null obično je lakše uvesti nego odmah dodati obavezan stupac. Uobičajeni slijed jest dodati stupac, implementirati kod koji zapisuje stari i novi prikaz, dopuniti podatke u kontroliranim serijama, provjeriti rezultat, a zatim nametnuti konačno ograničenje nakon što starije instance aplikacije nestanu.
Za velike tablice također razmotrite ponašanje zaključavanja, trajanje transakcija, replikaciju i mogućnosti vraćanja promjena. Tehnički valjana migracija još uvijek može biti operativno nesigurna ako predugo blokira prometnu tablicu.
Koristite API-je za očuvanje granica baze podataka
API bi trebao izražavati operacije domene umjesto da izravno izlaže tablice. Krajnja točka koja prihvaća proizvoljne stupce od klijenta povezuje vanjske potrošače s internim odlukama o pohrani. Također otežava razumijevanje autorizacije i validacije.
Umjesto da zapis narudžbe tretirate kao promjenjivu zbirku polja, modelirajte smislene radnje poput stvaranja narudžbe, dodavanja stavke, otkazivanja narudžbe ili potvrđivanja plaćanja. Backend tada može primijeniti autorizaciju, provesti prijelaze stanja i koordinirati transakcije bez potrebe da klijenti razumiju shemu.
To je još važnije u servisno orijentiranim sustavima. Baza podataka nije zajednički ugovor za integraciju. Servisi mogu objavljivati događaje ili izlagati API-je, ali dopuštanje da nekoliko sustava slobodno piše u iste tablice pretvara interne pojedinosti implementacije u krhki graf ovisnosti.
Operativni detalji dio su dizajna
Pouzdana shema treba pouzdane operacije oko sebe: sigurnosne kopije koje se mogu obnoviti, postupke migracije koji su testirani, nadzor sporih upita i neuspjelih poslova te pravila zadržavanja za podatke koji ne bi trebali živjeti zauvijek. Docker može učiniti lokalno postavljanje baze podataka ponovljivim, ali spremnik ne zamjenjuje planiranje trajne pohrane, upravljanje vjerodajnicama ni testiranje oporavka.
Također namjerno odlučite kako se prikazuju vrijeme, novac, identifikatori i brisanje. Pohranjujte novčane iznose u tipovima s fiksnom preciznošću ili manjim jedinicama u skladu s pravilima sustava. Vremenske oznake pohranjujte dosljedno i sačuvajte dovoljno konteksta za poslovno značenje. Dajte prednost izričitim pravilima mekog brisanja ili arhiviranja kada zapisi moraju ostati referencijalno vidljivi, umjesto da tiho brišete podatke o kojima drugi zapisi još ovise.
Shema je dugoročna odluka o proizvodu
Dobar dizajn baze podataka nije stvar stvaranja najsloženijeg dijagrama ni težnje čistoći pod svaku cijenu. Riječ je o tome da ispravno ponašanje bude lako, neispravno ponašanje teško, a buduće promjene razumljive. Promišljena shema daje PHP servisima jasnije odgovornosti, API-jima sigurnije ugovore, a timovima zajednički jezik za domenu.
Kada se očekuje da sustavi postanu inteligentniji, njihovi podaci najprije moraju postati pouzdaniji. Izgradite taj pouzdani temelj s izričitim odnosima, provedivim pravilima, namjernim putanjama upita i planovima razvoja koji poštuju produkcijsku stvarnost. Inteligencija iznad njega imat će na čemu čvrsto stajati.