Citat:
Pri modeliranju baze uvek se pravi kompromis između realnog (seka iz knjigovodstva) i aplikativnog (bata programer) modela. Ako ja imam složeni ključ od 3 ili 4 polja i u svakom upitu sam prinuđen da pišem par dodatnih uslova u where delu, normalno je da ću da dodam surogat ključ.
Druga recenica iz citata objasnjava zasto se koriste surogatni kljucevi - zato sto progarmera mrzi da pise JOIN i WHERE po nekoliko kolona umasto po jednoj. Pa sta ako moras da pises par ddatnih uslova/ To je tvoj posao za koji si placen. tesko/ Tough luck. Uvodjenje surogat kljuca otvara vrata za nevidjene stvari. Recimo,
Zadaci (SurogatID PK, RadnikID, ZadatakID) dozvoljava da se za RadnikId=1 i zdatakID=5 odradi ovo:
INSERT INTO Zadaci VALUES (1,1,5)
INSERT INTO Zadaci VALUES (2,1,5)
INSERT INTO Zadaci VALUES (3,1,5)
INSERT INTO Zadaci VALUES (4,1,5)
INSERT INTO Zadaci VALUES (5,1,5)
Znaci, 5 redova, isti radnik, isti zadatak. i sve je OK, jer zaboga PK je unique. Naravno, ovo ne dozvoljavamo u praksi, pa onda dodamo jos jedan unique index (RadnikID, ZadatakID). Eto, nema vise duplikata. jeste, ali imamo i dva indeksa. jedan po SurogatID, verovatno je taj i CLUSTERED, i jos jedan (RadnikID,ZadatakID), kpji nije clustered. I gde je tu performance improvement? Viska polje, koje je INT ili cak LongINt, dva indeksa. jedino poboljsanje jeste sto je naoko progarmeru lakse da napise JOIN kao
JOIN ON Zadaci AS Z ON Z.SurogatID=NekaTabela.SurogatID
umesto
JOIN ON Zadaci AS Z ON Z.RadnikID=NekaTableaRAdnik.ID AND Z.ZadatakID = NekaTabela.ZadatakID
I naravno, NekaTable imala bi samo SurohgatID za vezu sa Zadaci. Eto ustede - jedno polje se migrira u child tabelu, umesto dva.
amislite tableu IstorijaZadatka u koju se belzi sta je i kada uradjeno na nekom zadatku. Parent table je Zadaci a child atbela je IstorijaZadatka.
Varijanta 1: IstorijaZadatka (SurogatID,DAtum,StajUradjeno)
Ptanje glasi: Prikazati sve sta je neki radnik uradio i akda je uradio.
Posto imamo samo SurogatID za vezu sa Zadaci, onda nam je nophodan kveri da nam pklaze KOJI ranik je odradio Jednostavan SELECT koji daje sta nam treba:
SELECT I.SurogatID, I.DAtum, I.StajUradjeno, Z.radnikID
FROM IstorijaZadatka AS I
JOIN Zadaci ON I.SurogatID=Zadaci.SurogatID
Varijanta 2: IstorijaZadatka (RadnikID, ZadatakID, Datum, Sta jeUradjeno)
U ovom slucaju nam NE TREBA kveri koji povezujeIstorijaZadatka sa Zadaci. Select bi zigledao ovako:
SELECT RadnikID, ZadatakID, Datum, Sta jeUradjeno
FROM IstorijaZadatka
SELECT je select neko ce reci. Da li bas? Otkad je SELECT koji ima JOIN brrzi od selecta koji nema JOIN?
Znaci, upravo kveri za koji sebi pokusavata da olaksate pisanje, nece vam ni trebati ako migrirate slozeni kljucu child tabelu. Lakse je ne pisati kveri uopste, nego pisati najjednostavniji moguci kveri. Eto, i programer profitira ako se migrira slozeni kluc :-)
Ovo nisam ja izmislio, E. Codd je jos pre trideset godina rekao da se migrira ceo PK iz parent u child tabele. Onda je neko ustvrdio da je to teoretisanje i da je brze raditi sa surogat kljucevima. Mozda je tako bilo pre trideset godina, kompjuteri su bili sporiji i diskovi skuplji.
Nazalost, bez surogata se ne moze. Ima situacija kada u realnom sistemu ne postoji nista sto bi jednoznacno odredilo red u tabeli. Na primer - kasa u samousluzi. Racun koji dobijete je modelovan tabelom StavkeRacuna. Nije dobro da su stavke racuna modelovane ovako:
StavkeRacuna (RacunID, ArtiklID,Kolicina) PK (RacunID, ARtiklID)
Zasto? Pa svaki artikl moze da se pojavi na racunu tacno jedamput. Ako je korpa velika, i kupili ste 10 identicnih jogurta, ne znaci da ce kasir da skenira jedan i onda unese kolicinu. Kasir skenitra svaki artikl. Znaci, za 10 identicnih jogurta treba 10 redova u tabeli. Tu nam treba nesto da dobijemo PK. Nekakav brojac artikala na racunu. Ako ne prikazujemo taj brojac na racunu (redni broj artikla) onda je OK da stavimo na primer neki identity koji ce da obezbedi jedinstvenost. Ali, ako nam treba brojac stavki, i da ide od 1 pa nadalje, onda opet ne moze surogat key, mora da se nekako obezbedi brojac od 1 do N.