MainframeSupports
tip uge 13/2015:

En af de store udfordringer i DB2 har lige fra fødslen været generering af unikke stigende nøgleværdier. Første løsning var at have en tabel med een række, der indeholdt enten sidst genereret nøgle eller den næste. Denne tabel endte altid med at blive en efterspurgt ressource, som gav mange deadlock og timeout problemer. Så kom DB2 med såkaldte identity columns, hvor nøglegenereringen blev en del af tabeldefinitionen. De gav så andre problemer, såsom at komme ud af synkronisering og skabe huller i nummereringen. Desuden var det svært at kopiere data fra et miljø til et andet, da der let kunne komme nøglesammenfald.

Det seneste forsøg i kampen om at få kontrol over stigende nøglegenerering er de såkaldte sequences, som jeg har omtalt i anden sammenhæng. Her er nøglegenereringen adskilt fra tabeldefinitionen, og løsningen svarer til at have en tabel til nøglen, men uden deadlock/timeout problemerne. Der er dog stadig en udfordring omkring næste nøgleværdi, hvis data kopieres fra et miljø til et andet.

For nylig kom jeg så på en ide, som måske kan bruges til at løse alle udfordringerne med genererede nøgler. Jeg har ikke afprøvet den i OLTP sammenhæng, hvor det sagtens kan tænkes, at løsningen har sine udfordringer. Her er et eksempel på, hvad den går ud på:

INSERT INTO MYTABLE (KEYCOLUMN, COLUMNA, COLUMNB)
VALUES((SELECT VALUE(MAX(KEYCOLUMN),0) + 1 FROM MYTABLE), 'COLUMNA-VALUE', 'COLUMNB-VALUE')

Hvis du ikke allerede vidste det, så har det siden version 8 af DB2 været tilladt at benytte sub-selects som expressions stort set overalt. Kravet er, at sub-select'en returnerer netop een værdi. For at kunne håndtere start situationen med en tom tabel har jeg puttet en VALUE rundt om MAX(KEYCOLUMN) så max-værdien bliver nul. Ovenstående trick kan også bruges ved INSERT INTO SELECT ... FROM på følgende måde:

INSERT INTO MYTABLE (KEYCOLUMN, COLUMNA, COLUMNB)
SELECT ROWNUMBER() OVER() + (SELECT VALUE(MAX(KEYCOLUMN),0) FROM MYTABLE)
     , OTHER_COLUMNA, OTHER_COLUMNB
FROM OTHER_TABLE
WHERE ...

Fordelen ved ovenstående løsning frem for en SEQUENCE er, at man ikke skal spekulere over at sætte start-værdien for SEQUENCE'n, hvis tabellen fødes med data fra en anden kilde, hvor nøgleværdierne ikke genereres via SEQUENCE'n. Om løsningen er mere performance-tung end en SEQUENCE kan jeg ikke lige svare på. DB2 kan benytte en særlig accessvej, når den største værdi i den første kolonne i et index skal hentes. Kravet for, at ovenstående performer under alle forhold er, at der er et index på KEYCOLUMN.

Forrige danske tip        Last tip in english        Tip oversigten