Bij het ontwerpen van grote relationele databases nemen we vaak de beslissing om af te wijken van een normale vorm, d.w.z. denormalisatie.
De redenen hiervoor kunnen verschillend zijn, zoals een poging om de toegang tot de gespecificeerde gegevens te versnellen, beperkingen van het gebruikte platform/framework/ontwikkeltools en gebrek aan vaardigheden van een databaseontwikkelaar/ontwerper.
Strikt genomen is een verwijzing naar de kaderbeperkingen, enz. eigenlijk een poging om het gebrek aan vaardigheden te rechtvaardigen.
De gedenormaliseerde gegevens zijn een kwetsbaarheid, waardoor het gemakkelijk is om onze database in een niet-consistente (niet-integrale) staat te brengen.
Wat kunnen we hiermee?
Voorbeeld
In een database is er een tabel met enkele financiële operaties:de ontvangst en beschikking van fondsen op verschillende rekeningen.
We moeten altijd het saldo van de rekening weten.
In de genormaliseerde gegevens is het fondssaldo altijd een berekende waarde. We gaan het totaal van de ontvangsten berekenen zonder te debiteren.
Het is echter te duur om bij veel bewerkingen telkens het saldo te berekenen. Daarom is ervoor gekozen om het actuele saldo in een aparte tabel op te slaan. Hoe werken we de gegevens in deze tabel bij?
De oplossing is 'zoals gewoonlijk'
Vrijwel in alle informatiesystemen waarmee ik moest werken, werd deze taak uitgevoerd door een externe applicatie, die de bedrijfslogica implementeerde. Je hebt geluk als de applicatie eenvoudig is en er maar één punt voor gegevensverandering is, van het formulier in de gebruikersinterface. Maar wat als sommige importen, API's, applicaties van derden, enz. door verschillende mensen en teams worden uitgevoerd? Wat als er meerdere tabellen zijn met totalen in plaats van één? Wat als er meer dan één tabel met bewerkingen is?
Het wordt steeds moeilijker om te controleren of een ontwikkelaar een aantal tabellen heeft bijgewerkt bij het bijwerken van bewerkingen. De gegevens verliezen integriteit. Het rekeningsaldo komt niet overeen met de verrichtingen. Natuurlijk moeten testen dergelijke situaties aan het licht brengen. Onze wereld is echter niet ideaal.
Triggers
Als alternatief worden triggers gebruikt om de integriteit van gedenormaliseerde gegevens te controleren.
Ik heb gehoord dat triggers een database enorm vertragen, dus het heeft geen zin om ze te gebruiken.
Het tweede argument was dat alle logica in een aparte applicatie zit en dat het onredelijk is om bedrijfslogica op verschillende plaatsen te houden.
Laten we het uitzoeken.
Vertraging
Binnen de transactie wordt een trigger geactiveerd die de gegevens in de tabel wijzigt. De transactie kan pas worden voltooid als de trigger de vereiste stappen heeft uitgevoerd. Daarom is de conclusie dat triggers 'licht' moeten zijn.
Het voorbeeld van de 'zware' zoekopdracht in de trigger is als volgt:
update totals set total = select sum(operations.amount) from operations where operations.account = current_account where totals.account = current_account
Een query verwijst naar de tabel met bewerkingen en somt het totale bedrag op van bewerkingen voor het account .
Wanneer de database groter wordt, zal zo'n query steeds meer tijd en middelen kosten. We kunnen echter hetzelfde resultaat krijgen met de light-query van het volgende type:
update totals set total = totals.total + current_amount where totals.account = current_account
Wanneer u een nieuwe rij toevoegt, verhoogt deze trigger eenvoudig het totaal met het account zonder het te berekenen. Het totaal is niet afhankelijk van de gegevenshoeveelheid in tabellen. Het heeft geen zin om het totaal opnieuw te berekenen, omdat we er zeker van kunnen zijn dat de trigger elke keer afgaat bij het toevoegen van een nieuwe bewerking.
Het verwijderen of wijzigen van rijen gaat op dezelfde manier. De triggers van dit type zullen de bewerkingen niet vertragen, maar zorgen wel voor gegevenskoppeling en integriteit.
Elke keer dat ik "vertragingen" ervoer bij het toevoegen van gegevens aan een tabel met een trigger, was het een voorbeeld van zo'n "zware" query. In de meeste gevallen was het mogelijk om het te herschrijven in een "gemakkelijke" zoekopdracht.
Bedrijfslogica
We moeten functies die gegevensintegriteit bieden onderscheiden van de bedrijfslogica. In elk geval stel ik een vraag als de gegevens genormaliseerd waren, zouden we zo'n functie nodig hebben? Indien positief, is de functie bedrijfslogica. Indien negatief, is de functie het bieden van gegevensintegriteit. Je kunt deze functies in triggers stoppen.
Er is echter een mening dat het eenvoudig is om alle bedrijfslogica te implementeren via DBMS, zoals PostgreSQL of Oracle.
Ik hoop dat dit artikel zal helpen het aantal bugs in uw informatiesysteem te verminderen.
Natuurlijk ben ik verre van te denken dat alles wat hier is geschreven de ultieme waarheid is. In het echte leven is alles natuurlijk veel ingewikkelder. Daarom moet u in elk specifiek geval een beslissing nemen. Gebruik je technische denkwijze!
P.S.
- In het artikel vestigde ik de aandacht op het enige aspect van het gebruik van triggers als een krachtig hulpmiddel.
- De aanpak die in het artikel wordt beschreven, maakt het mogelijk om indexen in de Operations . te vermijden tabel, die op zijn beurt het proces van het toevoegen van gegevens aan deze tabel kan versnellen. Bij hoge volumes compenseert deze aanpak gemakkelijk de tijd die aan de trigger wordt besteed.
- Het is belangrijk om te begrijpen welke tools we moeten gebruiken. In dit geval vermijdt u veel problemen.