Database

Et database-system gør det muligt, at gemme en større mængde af information på en form, så informationen er maskinel omkostningslet at tilgå og opdatere. I modsætning til data, der er gemt i en fil kan flere computerprogrammer opdatere de samme data uden information tabes på grund af overskrivninger. Et andet mål er at adskille programmerne bedre fra lagringen af data, således at man kan tilføje felter til databasen uden nødvendigvis at skulle rette en masse programmer. Evt. kan en recompilering være nødvendig. Programmer, der skal bruge de nye data, skal naturligvis rettes. Endelig kan man med specielle views begrænse adgangen til visse oplysninger, både for læsning og for opdateringer, til bestemte programmer og bestemte brugere.

Krav til et databasesystem 
Et databasesystem skal stille følgende faciliteter til rådighed:
 Atomare transaktioner, hvilket betyder, at en ændring enten skal gennemføres helt eller også skal der ryddes så godt op, at det ser ud som om ændringen ikke er forsøgt gennemført.
 Konsistens De atomare transaktioner skal føre databasen fra en sammenhængende tilstand til en anden. Dette kræver, at de enkelte transaktioner er designet korrekt og hænger ikke kun på databasesystemet.
 Isolation To eller flere programmer, der bruger samme database, må ikke kunne se hinandens ændringer, før de er helt gennemførte. Der anvendes dog forskellige grader af isolation.
 Varighed Det skal sikres, at data ikke bare forsvinder. Det stiller krav til den anvendte hardware og krav om at skrivninger til disk laves, så data ikke kun lander i en cache undervejs. Det skal være muligt at genskabe hele databasen ud fra en backup og den efterfølgende log, således at man får samtlige gennemførte transaktioner med.

På engelsk kaldes disse krav om bestemte egenskaber for ACID-properties efter forbogstaverne i de engelske betegnelser atomicy, consistency, isolation og durability.

Nogle databasesystemer tillader replikering af databasen, således at systemet kan køre videre, selv om en kopi skulle gå ned. Eller man kan opnå hurtigere tilgang til databasen, når et program kan benytte den lokale kopi i stedet for at skulle over et netværk hver gang. Transaktioner i en distribueret database er mere komplicerede end for en enkelt database. Normalt benyttes en to-fase commit protokol.

Atomare transaktioner 
Hvis en transaktion kun omfatter læsning, vil den altid kunne startes forfra. Resten af afsnittet handler om transaktioner, der omfatter skrivning til databasen. Der findes flere måder at implementere atomare transaktioner på, men det almindeligste er at bruge en "skriv-foran-log" (write ahead log). Denne log vil i det følgende blive omtalt som en transaktionslog. Først skrives en beskrivelse af ændringen i transaktionsloggen og derefter gennemføres ændringen i selve databasen. Når en transaktion er gennemført, markeres den som gennemført i loggen.

Fejl håndteres forskelligt alt efter om det er fejl, der opdages af databasesystemet eller det er fejl, der opdages af det opdaterende program. Hvis fejl opdages af programmet, markeres transaktionen som fejlbehæftet, og alle opdateringer føres tilbage til udgangspunktet ved hjælp af oplysningerne i transaktionsloggen. Selvom databaseprogrammet finder en fejl, skal transaktionen så vidt muligt gennemføres. Hvis det er lykkedes at skrive transaktionen i loggen, gennemføres den fra oplysningerne her, ellers ikke. I visse tilfælde kan hensynet til korrekt isolation gøre, at en transaktion ikke kan gennemføres. I disse tilfælde bliver ændringerne ført tilbage, og det opdaterende program må forsøge at gennemføre transaktionen på ny.

Isolation 
Der opstår forskellige problemer, hvis forskellige programmer, der bruger den samme database, kan se hinandens ændringer inden de er helt gennemførte. Løsningen er, at isolere de enkelte databasetransaktioner fra hinanden. En høj grad af isolation sikrer, data hænger rigtigt sammen, men begrænser også parallelle opdateringer, hvilket kan give lange afviklingstider for de opdaterende programmer.

Et eksempel på problemet er en database med bankkonti, hvor to brugere/programmer søger at opdatere de samme konti samtidigt. Manglende isolation kunne føre til, at regnskabet ikke stemmer.

De mest gængse niveauer af isolation er fra det laveste til det højeste:
 Læs ikke gennemførte (read uncommitted): Ingen isolation. Et program kan læse data, som måske bliver tilbageført eller overskrevet senere.
 Læs gennemførte (read committed): Et program kan kun læse data, der er skrevet endeligt til databasen. Det er muligt, at de læste data ændres fra anden side inden transaktionen er slut.
 Gentagelige læsninger: Et program kan læse de samme data flere gange og få det samme resultat inden for den aktuelle transaktion.
 Serialisering: Ud over gentagelige læsninger er mulige, sikres det, at en transaktion ikke har kunnet læse data, der er slettet eller ændret inden transaktionen er gennemført. Data, der er tilføjet fra en anden transaktion, kan heller ikke ses.

I mange tilfælde er niveauet "læs gennemførte" tilstrækkeligt.

Varighed 
For at sikre, at data opbevares i databasen så længe, det er nødvendigt, er sikkerhedskopiering en nødvendighed. Det er i den sammenhæng vigtigt, at data hænger rigtigt sammen (er konsistente) inden backup foretages. Løsningen er, at etablere et kontrolpunkt (checkpoint).

Etablering af et kontrolpunkt kan ske på denne måde:
 Der lukkes af for nye transaktioner
 Transaktioner, der er i gang gennemføres
 Det sikres, at alle data er skrevet til disk
 Det markeres i databasens log, at der er lavet et kontrolpunkt
 Der laves backup og eventuelt anden vedligeholdelse
 Transaktionsloggen tømmes
 Der åbnes for transaktioner igen

Nogle databasesystemer kan sætte transaktioner i kø under oprettelse af et kontrolpunkt. Nogle systemer tillader at der kan tages backup af en kørende database.

Anvendelse af en database 
For at et databasesystem skal kunne bruges, skal flere ting være på plads. Der skal oprettes en database med en passende struktur. Det skal sikres, at de rette brugere har adgang til de dele af databasen der er relevant for dem. Der skal eventuelt fyldes data i fra en anden kilde som for eksempel et sæt filer. For at skille filer fra databasetabeller (der af og til også omtales som filer), kaldes de første ofte for flade filer.

Når databasen er på plads, kan man læse, oprette, ændre eller slette data i den. Ofte sker det med et program, der afvikles uden for databaseprogrammet som en klient/server-løsning.

Forskellige slags databaser 
Der findes overordnet nogle forskellige måder at implementere eller tilgå en database på. De præsenteres i de følgende afsnit.

Relationel database 
I en relationel database kan man oprette tabeller. Tabeller består af rækker (rows) af felter. De felter, i hver kolonne, der står i samme række, kaldes en post (tupple). Relationerne mellem tabellerne udgør den enkelte databases struktur. Reglerne for denne struktur kaldes referentiel integritet.

Det teoretiske grundlag for den relationelle datamodel er mængdelæren. I praksis er det dog de færreste systemer, der lever helt op til reglerne om mængder. For eksempel er det ofte muligt at have resultater af forespørgsler, der indeholder dubletter af rækker. Selve databasen indeholder naturligvis ikke disse dubletter, men kombinationen (join) af en post med et antal poster fra en anden tabel og en præsentation af resultatet som én tabel, nødvendiggør dette.

Ved læsning af data bruges tre grundlæggende operationer.

 Selektion: Find rækker, der opfylder en bestemt betingelse som for eksempel "alder = 42"
 Projektion: Vælg et antal kolonner fra en tabel. Det kunne være fornavn og efternavn.
 Krydsprodukt (join): Kombiner alle rækker i en tabel med alle rækker i en anden tabel.

Operationerne kan kombineres, så man kan lave forespørgsler i stil med "Kombiner persontabellen og adressetabellen. Find fornavn, efternavn og adresse på dem, der er 42 år gamle". Eller mere effektivt ville det ofte være at finde de personer, der opfylder alderskravet (fødselsdato før en given dato) og derpå kombinere resultatet med adressetabellen. Ideelt set bør databasesystemet selv finde den bedste metode.

Med det meget udbredte forespørgselssprog SQL kunne det se sådan ud:

 SELECT fornavn, efternavn, gade, husnr, postnr
 FROM persontb, adressetb
 WHERE persontb.adresseID = adressetb.adresseID
 AND persontb.alder = 42

DB2 blev udviklet af IBM ud fra teorierne om den relationelle database. Siden er adskillige andre kommet til.

Normalisering 
Man tilstræber som et ideal, at en relationel database er normaliseret. Formålet er at få en fleksibel database, dvs. at udbygninger ikke skal kræve store ændringer af relationerne mellem eksisterende tabeller. Der bør heller ikke være manglende oplysninger i en tabel (null-felter) eller gentagelse af den samme oplysning flere steder (redundans), da det kan medfører inkonsistens, hvis man glemmer at opdatere en af gentagelserne.

Man vil normalt også undgå at have felter, der er afledte, liggende i databasen, da de både er redundante og kan ændre sig. Et "godt" eksempel på et sådant problematisk felt er i det ovenstående eksempel personens alder. Principielt kan man blive tvunget til at gennemløbe hele databasen dagligt for at opdatere personernes aldre, hvis der er tale om "levende personer".

Der findes forskellige grader af normalisering, fra første normalform over femte normalform til Boyce-Codd normalform med stigende strikse krav til databasens opbygning.

Hensyn til svartider eller hensynet til at det skal være nemt for almindelige brugere af systemet at søge direkte i databasen, kan af og til tale for en delvis de-normalisering. Det bør være et velovervejet og bevidst valg.

Inverteret liste database 
Den inverterede liste minder meget om den relationelle database. Dog er det meget tydeligt, at den er opbygget af indices, og man kan benytte disse indices til at navigere gennem databasen, lige som man kan manipulere lister over udsøgte poster. Opbygningen af databasen har således stor indflydelse på programmørens muligheder for at navigere i databasen. Det første eksempel på denne type database er ADABAS, der er fra 1969.

Hierarkisk database 
Den hierarkiske databasetype er en af de ældste med en oprindelse tilbage i 1960'erne. IBMs database IMS, der blev udviklet til Apollo-programmet, er en hierarkisk database. Data er, som navnet siger, ordnet hierarkisk i træstrukturer med forældre/børn-relationer.

Til nogle formål er det den klart hurtigste databasetype der findes, men ulempen er, at data kun effektivt kan tilgås i den orden som den hierarkiske struktur dikterer. Ændres måden man vil tilgå data på, skal databasen reelt set omdesignes og data konverteres. Det er i nogle tilfælde muligt at tilgå data gennem en anden struktur med en anden ordning, selv om der rent faktisk er tale om de samme data.

I dag er den hierarkiske databasetype stort set erstattet af den relationelle pga. dennes større fleksibilitet.

Netværksdatabase 
I korthed er en netværksdatabase opbygget af "poster", organiseret i "post-typer". Mellem to post-typer kan der defineres en "set-type", hvor den ene post-type er "owner", og den anden post-type er "member". På en set-type kan der defineres et antal forskellige betingelser, der skal gælde, f.eks. sortering, éntydighed, hvordan søgning skal foregå, om sletning skal videreføres fra owner til member, og om en ny post kan indsættes i member uden kontrol af nøglen mod owner. Databasetypen blev søgt standardiseret under betegnelsen CODASYL.

Objektorienteret database 
En objektorienteret database er database baseret på objekter i en form svarende til den, der bruges i objektorienteret programmering. Der er endnu meget få databasesystemer, der fungerer på denne måde, men der findes flere programmeringsværktøjer, der giver mulighed for automatisk opdatering af en relationel database på baggrund af objekter. Som programmør slipper man ikke for at tænke på databasen, men meget af den trivielle programmering kan automatiseres.

Kilder 
 Fundamentals of database systems af Ramez Elmasri og Shamkant Navathe 
 An Introduction to Database Systems af C.J. Date, vol. I, 4. udgave 1986

Eksterne henvisninger 
 Bevaring af databaser 

 
Digital bevaring