Při navrhování velkých relačních databází se často rozhodujeme odklonit se od normální formy, tedy denormalizace.
Důvody mohou být různé, například snaha urychlit přístup ke specifikovaným datům, omezení používané platformy/rámce/vývojových nástrojů a nedostatek dovedností vývojáře/designéra databáze.
Přísně vzato, odkaz na rámcová omezení atd. je ve skutečnosti pokusem ospravedlnit nedostatek dovedností.
Denormalizovaná data představují zranitelnost, díky které je snadné uvést naši databázi do nekonzistentního (neintegrálního) stavu.
Co s tím můžeme dělat?
Příklad
V databázi je tabulka s některými finančními operacemi:příjem a nakládání s finančními prostředky na různých účtech.
Vždy potřebujeme znát zůstatek na účtu.
V normalizovaných datech je zůstatek fondu vždy vypočtenou hodnotou. Vypočítáme součet účtenek bez odečtení.
Je však příliš nákladné vypočítat zůstatek pokaždé, když existuje mnoho operací. Proto bylo rozhodnuto uložit skutečný zůstatek do samostatné tabulky. Jak aktualizujeme údaje v této tabulce?
Řešení je „jako obvykle“
Téměř ve všech informačních systémech, se kterými jsem musel pracovat, tuto úlohu zajišťovala externí aplikace, která implementovala business logiku. Máte štěstí, pokud je aplikace jednoduchá a existuje pouze jeden bod změny dat, z formuláře v uživatelském rozhraní. Co když však nějaké importy, API, aplikace třetích stran atd. provádějí různí lidé a týmy? Co když existuje několik tabulek se součty místo jedné? Co když existuje více než jedna tabulka s operacemi?
Je stále těžší sledovat, zda vývojář při aktualizaci operací aktualizoval spoustu tabulek. Data ztrácejí integritu. Zůstatek účtu neodpovídá operacím. Takové situace musí samozřejmě odhalit testování. Náš svět však není ideální.
Spouštěče
Alternativně se spouštěče používají k řízení integrity denormalizovaných dat.
Slyšel jsem, že spouštěče značně zpomalují databázi, takže jejich používání nedává smysl.
Druhým argumentem bylo, že veškerá logika spočívá v samostatné aplikaci a udržování obchodní logiky na různých místech je nerozumné.
Pojďme to zjistit.
Zpoždění
Uvnitř transakce se spustí spouštěč, který upraví data v tabulce. Transakci nelze dokončit, dokud spouštěč neprovede požadované kroky. Závěr je tedy takový, že spouštěče musí být „lehké“.
Příklad ‚těžkého‘ dotazu ve spouštěči je následující:
update totals set total = select sum(operations.amount) from operations where operations.account = current_account where totals.account = current_account
Dotaz odkazuje na tabulku s operacemi a sečte celkovou částku operací pro účet .
Když se databáze zvětší, bude takový dotaz spotřebovávat stále více času a zdrojů. Můžeme však získat stejný výsledek pomocí lehkého dotazu následujícího typu:
update totals set total = totals.total + current_amount where totals.account = current_account
Při přidávání nového řádku tento spouštěč jednoduše navýší součet o účet, aniž by jej počítal. Součet nezávisí na množství dat v tabulkách. Nemá smysl znovu počítat součet, protože si můžeme být jisti, že spouštěč se spustí pokaždé, když přidáte novou operaci.
Odstranění nebo úprava řádků probíhá stejným způsobem. Spouštěče tohoto typu nezpomalí operace, ale zajistí propojení dat a integritu.
Pokaždé, když jsem zažil „lagy“ při přidávání dat do tabulky pomocí triggeru, byl to příklad takového „těžkého“ dotazu. Ve většině případů bylo možné jej přepsat do „snadného“ dotazu.
Obchodní logika
Musíme odlišit funkce, které zajišťují integritu dat, od obchodní logiky. V každém případě se ptám, kdyby byla data normalizována, potřebovali bychom takovou funkci? Pokud je kladná, funkce je obchodní logika. Pokud je záporná, funkcí je zajistit integritu dat. Tyto funkce můžete zabalit do spouštěčů.
Existuje však názor, že je snadné implementovat veškerou obchodní logiku prostřednictvím DBMS, jako je PostgreSQL nebo Oracle.
Doufám, že tento článek pomůže snížit počet chyb ve vašem informačním systému.
Samozřejmě jsem dalek toho, abych si myslel, že vše, co je zde napsáno, je konečná pravda. V reálném životě je samozřejmě vše mnohem složitější. Proto se musíte rozhodnout v každém konkrétním případě. Použijte své inženýrské myšlení!
P.S.
- V článku jsem upozornil na jediný aspekt používání triggerů jako mocného nástroje.
- Přístup popsaný v článku umožňuje vyhnout se indexování v Operacích tabulky, což zase může urychlit proces přidávání dat do této tabulky. Při vysoké hlasitosti tento přístup snadno kompenzuje čas strávený na spoušti.
- Je důležité pochopit, jaké nástroje potřebujeme používat. V tomto případě se vyhnete mnoha problémům.