2009. március 10., kedd

GUID vs. Int kulcsok

A relációs adatbázisokban az adatokat táblákban tároljuk, ha pedig ezeket a táblákat valamilyen módon egymáshoz szeretnénk kapcsolni (naná, ettől lesz relációs az adatbázis), a táblák sorait jó ellátni valamilyen egyedi azonosítóval.
Eddig semmi nagy meglepetés.
Ha nincs olyan szerencsénk, hogy az elsődleges kulcs szerepére van egy jó jelöltünk, akkor kénytelenek vagyunk magunk egy mesterséges, bizonyosan minden rekordra egyedi azonosítót (surrogate key-t) csinálni. De milyen típusú legyen ez a kulcs? Többnyire egy automatikusan generált int lesz a jelölt, de használhatunk esetleg GUID-ot is. Milyen előnyökkel, illetve hátrányokkal jár egy globálisan egyedi azonosító?

Pró:

  • Könnyű merge és replikációs szenáriók: a kulcsaink tényleg egyedi kulcsok, nem csak az adott táblára, hanem az adatbázis többi táblájára, vagy más szervereken tárolt, akár teljes, akár részleges másolatokhoz képest is. Ezzel rendkívül egyszerűvé válnak az olyan feladatok, amikor az adatokat több táblába, több szerverre szeretnénk szétszórni, vagy a több táblában, több szerveren keletkezett adatokat szeretnénk egy helyre összegyűjteni (a duplikátumok kiszűrésével, nyilván).
    Ha nincs saját replikációs logikánk, hanem az SQL Server ilyen szolgáltatásait szeretnénk használni, akkor pedig mindenképp szükségünk lesz egy uniqueidentifier típusú mezőre (amit RowGuid-ként meg is kell jelölnünk).
  • Az Id generálás bárhol megtörténhet: az auto-increment integer azonosítók esetében az újonnan létrehozott rekordok (entitások, ha tetszik) azonosítója csak az adatbázisba való INSERTálás után képződik meg - ellenben maga az entitás általában "fönt", az alkalmazásunk üzleti logika rétegében. Amíg az új példányunk sikeresen perzisztálásra nem kerül, az Id-val nekünk kell bűvészkedni, esetleg bevállalni egy plusz DB roundtripet már példányosításkor (lehet, hogy fölöslegesen). Tranzakcionális mentéskor ROLLBACK esetén pedig külön öröm, hogy a már beállított Id-kat "vissza kell venni".
    Guid-nál ilyen gond nincs, maga az Id bárhol gerenálódhat, az biztosan egyedi lesz.

Kontra:

  • Nagyobb kulcsméret: míg az int 4 byte, a GUID adattípus négyszer akkora, 16 byte-nyi helyet foglal. Ennek természetesen ára van: tárhelyben, memória-igényben, hálózati sávszélességben, performanciában.
  • Nehéz olvasni, megjegyezni: Ez elsőre nagyon profánnak tűnhet, de gondoljunk bele, mennyivel egyszerűbb azt fejben tartani, hogy az Administrator Id-ja 1, mint azt, hogy {26D66F17-1297-44fd-AD83-FD102C8A41C9}. Vagy leírni egy olyan SELECT-et, hogy ...WHERE Id IN (1, 2, 3), mint egy olyat, hogy ...WHERE Id IN ('6FA9C7BC-A1F0-4B4E-A4CC-49EE3822E9E8', '47F1211C-61DB-4102-B103-3EED9AC8733F', 'B12A79BA-78B9-431C-BE71-0CF30DA37BF2'). Ha ezután az pont elolvasása után már kezd káprázni a szemünk a betűktől és a számoktól - pedig csak olvasásról van szó, gondoljunk bele, ha ezt be kell írni, ott pedig egy typo, és máris nem az történik, amit szeretnénk! -, valami kis képünk azért már lehet róla, hogy a GUID azonosítók árát fejlesztési élmény, hibakereshetőség, karbantarthatóság oldalról is meg kell fizetni.
    Ugyanennek a problémának egy másik vetülete, hogy ha az elemeink azonosítói megjelennek pl. egy webes alkalmazás URL-jeiben, akkor egy GUID azért lényegesen cifrábban néz ki, mint az, hogy "?Id=1" (ugyanakkor ez akár előny is lehet: egy támadási felülettel kevesebb, azt ugyanis nem nagy sakk kitalálni, hogy egy int kulcsos Users táblában lesz olyan user, akinek az azonosítója 0 vagy 1 - jó eséllyel pont az adminisztrátor -, míg GUID-nál ez nem triviális).
  • A GUID nem minden nyelven natív adattípus: bár a .NET támogatja a Guid típust, illetve az SQL uniqueidentifier típusának Guiddá- és visszaalakítását, ez nem minden nyelvben ilyen triviális. De még ha nem is tervezzük az adatbázis nem-dotnet nyelvből való kurkászását, könnyen lehet, hogy a kliensoldani JavaScript kódunkban szükség lesz az Id-kkal való varázslásra.
  • A GUID-ok nem szekvenciálisak, ellentétben az auto-generated integer kulcsokkal, amik szép monoton növekvőek (1, 2, 3, 4...).
    Ha egy ilyen mezőt megteszünk clustered key-nek, akkor az integer esetében az újonnal létrejövő entitások szépen az eddigiek után fűződnek, míg GUID esetében össze-vissza fognak a rekordok beszúródni a táblába, erős fragmentálódsához vezetve. Szerencsére ezen lehet segíteni.

De már csak egy későbbi alkalommal.

0 megjegyzés:

Megjegyzés küldése