15. April 2024

Brug UUID’er i din database

Internettet bugner med guides omhandlende hvordan du lærer at programmere. Desværre, så er der et kæmpe gab fra begynderguides til de mere avancerede emner. Hvad med de små “cowboy-tricks” som guides ikke lærer dig? Får vi bragt dem på bane, får vi ultimativt bedre IT-løsninger. Jeg kalder dem cowboy-tricks, fordi “best practice”-terminologien ikke rigtig holder særlig længe i IT-branchen: Det der anbefales i dag, kan være yt allerede i morgen.

Eksempel: Man kan stadig finde 20 år gamle PHP-guides på nettet, der instruerer folk i at bruge den uddaterede MD5-hashingalgoritme. Det er lidt trist, når den slags guides ofte er nybegynderes første kontakt med webprogrammering, for så får man ofte den opfattelse, at det er sådan, man gør. Se istedet password_hash().

Programmørfællesskabet Stack Overflow er der, hvor du finder de friskeste tråde omkring forskellige aspekter ved programmering. Finder du de tråde, så læs dem, det er der man virkeligt lærer: Når folk argumenterer for, hvorfor de vælger eller fravælger den løsningsmodel, de eller andre brugere har præsenteret i forumtråden. Og det er måske den bedste hjælp, når vi giver viden videre til andre. Det, der er særligt godt ved StackOverflow, når sitet viser sig fra sin bedste side, er at folk gerne samler årgamle tråde op for at tilføje opdateret viden.

Nå, men tilbage til UUID’erne…

Begyndelsen

Noget af det første du lærer i en guide, er hvordan du sætter din database op, sammen med den programmerings-platform, du nu interesserer dig for. De lærer dig at sætte en ID-kolonne op med fortløbende autonummerering og en primærnøgle, såsom:

ID Navn
1 Anna
2 Gylda
... ...

Det er fundamentet for alle databaseprojekter. Men midt i al simpliciteten, så slipper de fleste guides ret ofte tøjlerne, der hvor man går fra teori til praksis. Og det er et problem, fordi en database, hvor man identificerer de enkelte poster via et fortløbende ID er irriterende besværlig at arbejde med, hvis den skal kombineres med andre datakilder.

Sov godt om natten

Forestil dig, at du er ved at programmere et nyt artikelsystem på en hjemmeside. Du har en tabel i din database med flere tusinde rækker. Fra 1 - 1000. En dag kommer din chef og vil have dig til at kombinere den gamle artikeltabel med en anden tabel, for I har lige fusioneret med et nyt firma. Men der er et problem: Den anden artikeltabel har også rækker fra 1 - 1000.

Løsningen vil være, at de friskeste data gives ID’erne 1001 og fremefter… I mindre setups, hvor data ikke nødvendigvis skal ordnes kronologisk vil det ikke være et problem lige med det samme, men det er alt andet lige en skrøbelig løsning.

For du har jo normaliseret databasen, ikke? ;-) Skal du stadig have sammenhæng i dine data skal poster i evt. afledte tabeller også have det nye fortløbende ID, så det er tungen lige i munden ved kørsel af en dataimport. Du skal være 100% sikker på, at der ikke er dublerede Id’er. Hvis din tabels ID-kolonne har en primærnøgle, så kan du være sikker på, at databaseserveren sender eder og bespottelser i din retning, hvis den importerer et ID, der allerede findes.

Der må da være en lettere metode, der kan sikre din nattesøvn?

UUID’er to the rescue!

UUID’er - Universally Unique Identifier (UUID) - er unikke nøgler på maks. 128 bits længde. De ses ofte repræsenteret som en tekststreng på 32 karakterer hexadecimalt - f.eks 550e8400-e29b-41d4-a716-446655440000, men kan grundet makslængden på 128-bit også repræsenteres udelukkende som heltal. Det gør databaseserveren MariaDB/MySQL f.eks, og det forvirrede mig i starten.

Hvis du er masochist-typen kan du endda repræsentere et UUID binært med 0′er og 1-taller. Men så er vi vist ude i selvpineri, det kan jeg ikke se nogen fornuftig idé i ;-) I Assembly begyndte man også at bruge hexadecimal notation, fordi det var kortere og nemmere at arbejde med end binær notation.

Intet sammenfald

Givet en 128-bit størrelse, så er det meget usandsynligt, at to genererede nøgler nogensinde vil være ens. Wikipedia nævner i et afsnit om UUID’er, at blandt 103 trillioner generede UUIDv4-strenge, så er sandsynligheden for et nøgle-sammenfald 1:1.000.000.000 (1 milliard).

Ergo kan vi bestemt godt bruge dem som vores fikspunkt for datafletning. Du får en databasepost med en kolonne hvor data, der refereres til, altid er unikt og det bliver yderligere en fordel og et absolut must, hvis du en dag skal arbejde med data, der befinder sig i et servercluster, hvor forskellige servere udveksler data med hinanden (aka. distribuerede data).

Du kan også med fordel bruge UUID’er, når data eksporteres ud i et andet format, såsom JSON eller XML, fordi du kan referere tilbage til den oprindelige post. Det kan der så være sikkerhedsmæssige overvejelser til, at man IKKE vil gøre, men det er op til den, der implementerer IT-løsningen.

Lidt slutovervejelser

Måske synes du det er overkill at bruge UUID’er i dit projekt, men det er altid fint at tænke langsigtet, også selvom dine projekter starter med at være små og afgrænsede. Måske får du en dag behov for at skalere op og bruge en distribueret databaseløsning, så er det et absolut must, at du kan identificere dine data via en unik identifier på tværs af noderne i dit servercluster.

Selvfølgelig skal du overveje om det er umagen værd, og der kan være ydelsesmæssige ulemper ved at bruge UUID’er som primærnøgle, fordi størrelsen af UUID-datatypen er 4 gange større, end hvis du vælger at indeksere en kolonne med heltal (128-bit vs 32-bit) og det er også omstændigt at referere et UUID, hvis du ofte JOIN’er resultater på tværs af flere tabeller. Men om det er et ydelsestab, der er til at bære eller ej, det kan kun en test afsløre.

Jeg plejer at helgardere ved at bruge både en autonummereret ID-kolonne og en UUID-kolonne, der ikke indekseres på, så er både jeg og databasen glad, for så er der forskellige muligheder for at referere og indeksere samme datapost.

For at opsummere hele opslaget: Brug kun et fortløbende heltal som ID til at referere til poster internt i databasen. Det id bør på intet tidspunkt eksponeres ude i det fri. Skal du referere til en databasepost ifm. din programmering, så benyt altid det oprettede UUID.

Kildelinks

Wikipedia: Universally unique identifier
Programmørforum: Stack Overflow
Udvikleren.dk: Normalisering baseret på primærnøgler

Add comment

Fill out the form below to add your own comments