RSS

Jak generować klucze główne w bazie danych

Liczba odsłon: 360

Każda krot­ka ba­zy da­nych mu­si po­sia­dać atry­bu­ty jed­no­znacz­nie iden­ty­fi­ku­ją­ce ją w ra­mach re­lac­ji, do któ­rej na­le­ży. Minimalny zbiór ta­kich atry­bu­tów na­zy­wa­my klu­czem kan­dy­du­ją­cym (ang. can­di­da­te key), zaś je­den wy­bra­ny klucz kan­dy­du­ją­cy sta­je się klu­czem głów­nym (ang. pri­ma­ry key). Gdy nie moż­na wy­ło­nić na­tu­ral­ne­go klu­cza kan­dy­du­ją­ce­go, wpro­wa­dza się sztucz­ny atry­but, od któ­re­go do­bo­ru za­le­ży wy­go­da uży­wa­nia da­nych oraz wy­daj­ność ba­zy.

Przykła­do­wo, w re­lac­ji opi­su­ją­cej oso­by, za­wie­ra­ją­cej atry­bu­ty ta­kie jak imio­na, naz­wis­ko i da­ta uro­dze­nia, klu­czem kan­dy­du­ją­cym mógł­by być kom­plet tych in­for­mac­ji. Jest to jed­nak nie­ko­rzyst­ne z dwóch po­wo­dów. Po pierw­sze, jak­kol­wiek ma­ło jest to praw­do­po­dob­ne, mo­że się jed­nak zda­rzyć, że te­go sa­me­go dnia uro­dzą się oso­by o tych sa­mych imio­nach oraz naz­wi­sku. Po dru­gie, wy­szu­ki­wa­nie in­for­mac­ji za po­mo­cą tak ob­szer­ne­go klu­cza by­ło­by nie­wy­god­ne i nie­efek­tyw­ne, a prze­de wszyst­kim pro­wa­dzi­ło­by do nad­mia­ro­wo­ści za­pi­su.

Klucz nu­me­rycz­ny

Najprost­szym spo­so­bem roz­wią­za­nia te­go prob­le­mu jest na­da­nie każ­dej krot­ce uni­ka­to­we­go nu­me­ru. Taki klucz nu­me­rycz­ny jest ge­ne­ro­wa­ny auto­ma­tycz­nie przez ba­zę da­nych za po­mo­cą me­cha­niz­mu sek­wen­cji. Najczęściej pierw­sza do­da­wa­na krot­ka otrzy­mu­je nu­mer 1, a każ­da ko­lej­na o je­den więk­szy.

W ra­zie usu­wa­nia krot­ki jej nu­mer po­zos­ta­je nie­wy­ko­rzy­sta­ny. Zapobie­ga to przy­pad­ko­we­mu od­wo­ła­niu się do usu­nię­tych da­nych w przy­pad­ku, gdy w pew­nym ze­wnętrz­nym źród­le da­nych, nie zwią­za­nym spój­no­ścią od­nie­sień, za­pi­sa­ne są war­toś­ci klu­cza sta­no­wią­ce od­nie­sie­nia. Powoduje to, że klucz głów­ny re­lac­ji, w któ­rych wy­stę­pu­je du­żo ope­rac­ji wsta­wia­nia i usu­wa­nia kro­tek, ma co­raz więk­szą war­tość śred­nią. Konieczne jest za­tem sto­so­wa­nie od­po­wied­nio po­jem­ne­go ty­pu licz­bo­we­go. Nawet w ma­łych re­lac­jach nor­mą są klu­cze 32-bi­to­we, żad­ną eks­tra­wa­gan­cją nie są obec­nie klu­cze 64-bi­to­we, a cza­sem sto­su­je się na­wet war­toś­ci 128-bi­to­we. W ten spo­sób archi­tekt ba­zy da­nych mo­że mieć pew­ność, że przez kil­ka­naś­cie naj­bliż­szych lat – na­wet przy spo­rej ro­ta­cji kro­tek – war­toś­ci klu­cza głów­ne­go nie osiąg­ną gra­ni­cy ty­pu licz­bo­we­go.

Klucze licz­bo­we są też wy­god­ne w uży­ciu. W cza­sie roz­wo­ju i te­stów struk­tu­ry ba­zy da­nych ich war­toś­ci są ma­łe i łat­wo roz­poz­na­wal­ne dla lu­dzi. Ich sek­wen­cyj­ny cha­rak­ter po­wo­du­je, że moż­na je wy­ko­rzys­ty­wać do po­rząd­ko­wa­nia kro­tek w ko­lej­noś­ci wpro­wa­dza­nia ich do re­lac­ji.

Największą wa­dą klu­czy licz­bo­wych jest peł­na za­leż­ność klienta od ba­zy da­nych. Każda ope­rac­ja wpro­wa­dze­nia krot­ki do re­lac­ji mu­si być wy­ko­na­na w ra­mach jed­nej tran­sak­cji z po­bra­niem ko­lej­nej war­toś­ci z sek­wen­cji. Nie moż­na też przy­go­to­wać zbio­ru kro­tek bez po­łą­cze­nia z ba­zą da­nych, gdyż nie jest moż­li­we okreś­le­nie war­toś­ci klu­cza, z ja­ki­mi zo­sta­ną wsta­wio­ne. Utrudnia to zna­czą­co wszel­kie­go ro­dza­ju syn­chro­ni­za­cję da­nych.

Do za­let klu­czy licz­bo­wych moż­na z kolei za­li­czyć wy­so­ką wy­daj­ność. Przetwarza­nie liczb 32- i 64-bi­to­wych nie sta­no­wi żad­ne­go prob­le­mu dla obec­nie sto­so­wa­nych mi­kro­pro­ce­so­rów, a ge­ne­ro­wa­nie in­dek­sów na pod­sta­wie ciąg­łe­go zbio­ru war­toś­ci jest pros­te i szyb­kie.

Mechanizm hi/lo

Pewnym udos­ko­na­le­niem tech­ni­ki klu­czy licz­bo­wych jest me­cha­nizm hi/lo. Polega on na po­dzie­le­niu prze­strze­ni war­toś­ci klu­cza licz­bo­we­go na pod­zbio­ry. Najprost­szym roz­wią­za­niem jest po­dział ba­zu­ją­cy na bi­nar­nym za­pi­sie liczb, acz­kol­wiek moż­li­we jest za­sto­so­wa­nie do­wol­ne­go po­dzia­łu da­ją­ce­go się zal­go­ryt­mi­zo­wać.

Sekwencja klu­cza głów­ne­go okre­śla w ta­kim przy­pad­ku tyl­ko bar­dziej zna­czą­cą część war­toś­ci klu­cza. Klient otrzy­mu­je na wy­łącz­ność nie jed­ną war­tość klu­cza, lecz ca­ły pod­zbiór. W ra­mach te­go pod­zbio­ru mo­że przy­go­to­wać do­wol­ną licz­bę kro­tek ze wstęp­nie uzu­peł­nio­ny­mi już war­toś­cia­mi klu­cza głów­ne­go, gdyż nie ist­nie­je ry­zy­ko po­wsta­nia kon­flik­tu. Wymagany jest do te­go wy­łącz­nie je­den kon­takt z ba­zą da­nych i jed­na, krót­ka trans­akcja.

Technika ta za­cho­wu­je w za­sa­dzie wszyst­kie za­le­ty i wa­dy klu­czy licz­bo­wych. Wyjątkiem świad­czą­cym na jej ko­rzyść jest wspom­nia­na wy­żej moż­li­wość przy­go­to­wy­wa­nia kro­tek przy kon­tak­cie z ba­zą da­nych ogra­ni­czo­nym do mi­ni­mum. Niestety, po­wo­du­je to utra­tę ciąg­ło­ści war­toś­ci klu­cza głów­ne­go, co utrud­nia pra­cę pro­gra­mis­ty oraz – co istot­niej­sze – zmniej­sza spraw­ność me­cha­niz­mów in­dek­so­wa­nia.

Identy­fi­ka­to­ry glo­bal­nie uni­ka­to­we

Rozwią­za­niem prob­le­mu ge­ne­ro­wa­nia war­toś­ci klu­cza głów­ne­go bez kon­tak­tu z ba­zą da­nych są iden­ty­fi­ka­to­ry glo­bal­nie uni­ka­to­we (GUID, ang. glo­bal­ly uni­que iden­ti­fiers lub UUID, ang. uni­ver­sal­ly uni­que iden­ti­fiers). Są one 128-bi­to­wy­mi war­toś­cia­mi licz­bo­wy­mi ge­ne­ro­wa­ny­mi al­go­ryt­micz­nie, z op­cjo­nal­nym uwzględ­nie­niem pew­nych uni­ka­to­wych cech kom­pu­te­ra, któ­ry wy­zna­cza te war­toś­ci.

Wbrew naz­wie, war­toś­ci GUID nie da­ją gwa­ran­cji uni­ka­to­wo­ści. Ryzyko po­wsta­nia ko­li­zji jest jed­nak na ty­le ma­łe, że w prak­ty­ce po­mi­ja się je.

Najważniej­szą za­le­tą wy­ni­ka­ją­cą ze sto­so­wa­nia GUID ja­ko war­toś­ci klu­czy głów­nych jest moż­li­wość ge­ne­ro­wa­nia war­toś­ci klu­czy bez kon­tak­tu z ba­zą da­nych. Jest to szcze­gól­nie istot­ne w za­sto­so­wa­niach mo­bil­nych, w któ­rych nie moż­na za­pew­nić sta­łe­go po­łą­cze­nia z ba­zą. Na pod­sta­wie wy­ge­ne­ro­wa­nych klu­czy moż­na two­rzyć też wstęp­nie wię­zy od­nie­sień, bez ko­niecz­noś­ci ich mo­dy­fi­ko­wa­nia w mo­men­cie wpro­wa­dza­nia kro­tek do re­lac­ji.

GUID zna­czą­co ułat­wia­ją też im­ple­men­tac­ję re­pli­ka­cji i syn­chro­ni­za­cji. Elementy o tym sa­mym GUID znaj­du­ją­ce się w dwóch róż­nych re­lac­jach moż­na trak­to­wać ja­ko re­pli­ki. Całość prob­le­mu syn­chro­ni­za­cji da­nych spro­wa­dza się w tym mo­men­cie do wy­zna­cze­nia kie­run­ku i za­kre­su zmian w da­nych.

Niestety, glo­bal­nie uni­ka­to­we iden­ty­fi­ka­to­ry ma­ją też swo­je wa­dy. Przede wszyst­kim, zaj­mu­ją 16 baj­tów — dwu- lub czte­ro­krot­nie wię­cej niż iden­ty­fi­ka­to­ry licz­bo­we. Jest to szcze­gól­nie istot­ne w re­lac­jach za­wie­ra­ją­cych wie­le klu­czy ob­cych. Większy roz­miar ozna­cza przy tym nie tyl­ko więk­szą za­ję­tość pa­mię­ci ma­so­wej, ale też niż­szą wy­daj­ność prze­twa­rza­nia: w pa­mię­ci fi­zycz­nej zmieś­ci się mniej kro­tek i in­dek­sów, a sa­mo po­rów­ny­wa­nie war­toś­ci GUID za­miast pros­te­go odej­mo­wa­nia (dwie in­struk­cje ma­szy­no­we) mu­si być rea­li­zo­wa­ne w dwóch (czte­ry in­struk­cje) lub na­wet czte­rech (osiem in­struk­cji) kro­kach.

Utrudnio­ne jest też ge­ne­ro­wa­nie in­dek­sów umoż­li­wia­ją­cych szyb­kie wy­szu­ki­wa­nie kro­tek. Wartości GUID są du­że i nie­ciąg­łe, za­tem ba­za da­nych mu­si sto­so­wać al­bo ob­szer­ne in­dek­sy, al­bo prost­sze funk­cje skró­tu, skut­ku­ją­ce więk­szą licz­bą ko­li­zji. Z tym moż­na jed­nak wal­czyć, sto­su­jąc częś­cio­wo sek­wen­cyj­ne war­toś­ci GUID: praw­dzi­wie lo­so­wo wy­zna­cza­na jest tyl­ko pierw­sza war­tość, a ko­lej­ne róż­nią się tyl­ko na kil­ku po­zyc­jach.

Istotne jest też to, że iden­ty­fi­ka­to­ry GUID są ma­ło czy­tel­ne dla czło­wie­ka. Utrudnia to pra­cę pro­gra­mis­ty chcą­ce­go ręcz­nie zwe­ry­fi­ko­wać po­praw­ność za­pi­sów w ba­zie da­nych lub spraw­dzić, czy ge­ne­ro­wa­ne ze­sta­wie­nia za­wie­ra­ją właś­ci­we klu­cze. Z dru­giej stro­ny, wy­so­ka zmien­ność GUID po­wo­du­je, że du­żo łat­wiej jest wy­kryć przy­pad­ko­we uży­cie nie­właś­ci­wej war­toś­ci (na przy­kład na sku­tek po­mył­ko­we­go uży­cia in­ne­go atry­bu­tu).