Når vi designer store relationelle databaser, træffer vi ofte en beslutning om at afvige fra en normal form, dvs. denormalisering.
Årsagerne til dette kan være forskellige, såsom et forsøg på at fremskynde adgangen til de specificerede data, begrænsninger af den brugte platform/ramme/udviklingsværktøjer og manglende færdigheder hos en databaseudvikler/designer.
Strengt taget er en henvisning til rammebegrænsningerne osv. faktisk et forsøg på at retfærdiggøre manglen på færdigheder.
De denormaliserede data er en sårbarhed, hvorigennem det er nemt at bringe vores database til en ikke-konsistent (ikke-integral) tilstand.
Hvad kan vi gøre med dette?
Eksempel
I en database er der en tabel med nogle finansielle operationer:modtagelse og afhændelse af midler på forskellige konti.
Vi skal altid kende saldoen på kontoen.
I de normaliserede data er fondsbeholdningen altid en beregnet værdi. Vi skal beregne summen af kvitteringerne uden debitering.
Det er dog for dyrt at beregne saldoen hver gang, når der er mange operationer. Derfor blev det besluttet at gemme den faktiske saldo i en separat tabel. Hvordan opdaterer vi dataene i denne tabel?
Løsningen er 'som sædvanlig'
Næsten i alle informationssystemer, som jeg skulle arbejde med, blev denne opgave udført af en ekstern applikation, som implementerede forretningslogikken. Du er heldig, hvis applikationen er enkel, og der kun er ét dataskiftepunkt, fra formularen i brugergrænsefladen. Men hvad nu hvis der er nogle importer, API'er, tredjepartsapplikationer osv. udført af forskellige personer og teams? Hvad hvis der er flere tabeller med totaler i stedet for én? Hvad hvis der er mere end én tabel med operationer?
Det bliver sværere at overvåge, om en udvikler opdaterede en masse tabeller ved opdatering af operationer. Dataene mister integritet. Kontosaldoen svarer ikke til driften. Selvfølgelig skal test afsløre sådanne situationer. Vores verden er dog ikke ideel.
Udløsere
Som et alternativ bruges triggere til at kontrollere integriteten af denormaliserede data.
Jeg hørte, at triggere sænker en database meget, så det giver ingen mening at bruge dem.
Det andet argument var, at al logikken ligger i en separat applikation, og at det er urimeligt at holde forretningslogikken forskellige steder.
Lad os finde ud af det.
Forsinkelser
En trigger udløses inde i transaktionen, der ændrer dataene i tabellen. Transaktionen kan ikke gennemføres, før triggeren har udført de nødvendige trin. Derfor er konklusionen, at triggere skal være 'light'.
Eksemplet på den "tunge" forespørgsel i triggeren er som følger:
update totals set total = select sum(operations.amount) from operations where operations.account = current_account where totals.account = current_account
En forespørgsel henviser til tabellen med handlinger og opsummerer det samlede beløb af operationer for kontoen .
Når databasen øges, vil en sådan forespørgsel forbruge mere og mere tid og ressourcer. Vi kan dog modtage det samme resultat ved at bruge den lette forespørgsel af følgende type:
update totals set total = totals.total + current_amount where totals.account = current_account
Når du tilføjer en ny række, vil denne trigger blot øge totalen med kontoen uden at beregne den. Summen afhænger ikke af datamængden i tabeller. Det giver ingen mening at beregne totalen igen, da vi kan være sikre på, at triggeren udløses hver gang, når der tilføjes en ny operation.
Fjernelse eller ændring af rækker behandles på samme måde. Udløserne af denne type vil ikke bremse driften, men vil sikre datakobling og integritet.
Hver gang jeg oplevede "lags", når jeg tilføjede data til en tabel med en trigger, var det et eksempel på sådan en "tung" forespørgsel. I de fleste tilfælde var det muligt at omskrive det i en "let" forespørgsel.
Forretningslogik
Vi skal skelne funktioner, der giver dataintegritet, fra forretningslogikken. I hvert tilfælde stiller jeg et spørgsmål, hvis dataene var normaliserede, ville vi have brug for en sådan funktion? Hvis den er positiv, er funktionen forretningslogik. Hvis negativ, er funktionen at give dataintegritet. Du kan pakke disse funktioner ind i triggere.
Der er dog en opfattelse af, at det er nemt at implementere al forretningslogikken gennem DBMS, såsom PostgreSQL eller Oracle.
Jeg håber, at denne artikel vil hjælpe med at reducere antallet af fejl i dit informationssystem.
Selvfølgelig er jeg langt fra at tro, at alt, der er skrevet her, er den ultimative sandhed. I det virkelige liv er alting selvfølgelig meget mere kompliceret. Derfor skal du tage stilling i hver konkret sag. Brug din tekniske tankegang!
P.S.
- I artiklen henledte jeg opmærksomheden på det eneste aspekt ved at bruge triggere som et kraftfuldt værktøj.
- Den fremgangsmåde, der er beskrevet i artiklen, gør det muligt at undgå indekser i Operations tabel, hvilket igen kan fremskynde processen med at tilføje data til denne tabel. Ved høje volumener kompenserer denne tilgang nemt for den tid, der bruges på aftrækkeren.
- Det er vigtigt at forstå, hvilke værktøjer vi skal bruge til. I dette tilfælde vil du undgå mange problemer.