[ MatezYU @ 08.11.2010. 10:07 ] @
Interesuje me da li je neko od vas razvijao sopstveni brojac rednih brojeva umesto postavljenog identity-ja nad kolonom?
Potrebno mi je za sledecu situaciju. Kada se otvori nova forma za unos sloga da se pojavi naredni broj. Ako korisnik odustane od unosa, taj broj kasnije mora biti opet ponudjen sledecem korisniku. Takodje ako vise korisnika odjednom ide na unos novog sloga da se svakom dodeljuje razlicit broj.
Da li je neko razvijao ovakav sistem?
[ mmix @ 08.11.2010. 10:48 ] @
Tehnicki na samom SQLu nemas nacina da to uradis a da valja. Jedini nacin je da udaris X holdlock na tabelu ali onda nista od vise korisnika istovremeno.

Alternativa moze da se uradi na aplikacionom nivou, da serijalizujes upise kroz neki servis koji ce insertovati jedan po jedan kroz table lock. U svakoms lucaju bih ja taj business ID razdvojio od SQL identity ID-a (dakle zadrzi autoidentity polje za koje te bas briga dal ima rupa i preko kojeg ces raditi reference a pored njega imaj unique int polje koje ti kontrolises. Nije bas 3NF ali radi a i ne moras da se bakces sa resetovanje identity countera posle rollbacka.
[ MatezYU @ 08.11.2010. 14:11 ] @
Da, logika brojaca mi se vec nalazi u business delu (van sql server-a).
Identity kolonu sam zadrzao u tabeli za uspostavljanje relacije sa ostalim tabelama.
Za potrebu brojaca sam napravio novu kolonu brojac.
Interesuju me ideje - da li je neko vec realizovao nesto slicno.
Trenutno na ovaj nacin radi sistem: kada korisnik otvara formu dodeljuje mu se novi broj (iz pomocne tabele se cita trenutna vrednost brojaca i uvecava za jedan). Ovo je u transakciji. Drugi korisnik koji otvara formu dobija naredni broj itd. Ako prvi korisnik odustane od unosa, brojac se vraca u tabelu i dobija oznaku da je neiskoristen. Naredni koji bude otvorio novu formu dobice taj broj koji stoji u tabeli kao neiskoristen. Nedostatak ovoga je ako se desi nesto nepredvidjeno, tj. ako se ne klikne na formi odustani (recimo nestane struje ili dodje do prekida u programu) - taj dodeljeni slog se nece upisati u tabelu da je neiskoristen. Tj. ostace rupa u brojacima.
[ mmix @ 08.11.2010. 16:45 ] @
Ako ti broj ne treba do kraja transakcije onda mozes da odlozis dodelu do sameog inserta, time mozes da iskoristis kratkotrajnu X transakciju da napravis minimalni impact

transakcije moraju da budu serializovane

Code:

declare @num int;

begin transaction serializable
-- nadji max i pri tome zakljucaj celu tabelu, tablockx = tablock holdlock xlock ovo sprecava druge da urade ovu istu instrukciju (ali sprecava i klasican select)
select @num = max(mojid)+1 from tabela with (TABLOCKX)
insert into tabela (mojid, polje, ...) values (@num, ...)
commit


AKo dvoje krenu u isti kod samo jedan ce proci u select @num, drugi ce da blokira dok ti ne zavrsis ceo insert (commit), tek onda ce moci da uradi select i da dobije sledeci broj iza ovog.

[ MatezYU @ 09.11.2010. 16:30 ] @
Hvala!

A kako bih mogao da odradim lock na nivou reda?
[ mmix @ 09.11.2010. 20:26 ] @
A sta bi dobio sa istim? Mislim da ne bi ni mogao, al moram da proverim. Ako uradis samo obican exclusive lock mislim da ce ti ga SQL server eskalirati prvo na page a onda na table lock zbog agregatne funkcije MAX(). Al ne bih tvrdio 100%, provericu sutra.

[ MatezYU @ 09.11.2010. 20:55 ] @
Ok.
Mislio sam zbog broja korisnika i performansi (vise njih bi lock-ovalo tabelu).
Ne znam da li bi radilo eventualno brze ako bi se samo red lock-ovao.
Tada bi ostali korisnici mogli da gadjaju druge redove a cekalo bi se samo kada vise korisnika gadja isti red.
[ mmix @ 10.11.2010. 08:54 ] @
Ok, nasao sam ti mislim najoptimalnije resenje ali uz rizik. Poenta je da udaris unique desc index na mojID (DESC, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) i umesto with (TABLOCKX) koristi with (XLOCK).

Onda ce gornji kod umesto da eskalira lockove zakljucati samo poslednji indeksni kljuc i uzece samo IX na page sa poslednjim redom. Svi selecti koji ne ukljucuju skeniranje poslednjeg mojid kljuca (orderby i where nad mojid koji ukljucuje poslednji red) ce proci bez cekanja, takodje dve transakcije koje hoce ovaj kontrolisani insert ce cekati jedna na drugu (druga ce da zakaci X lock na kljucu i morace da ceka commit prve).

Problem i rizik je sto transakcija ne drzi X lock ni na redu ni na page-u i ako neko sa strane (van ove skripte) uradi insert u tabelu tokom transakcije proci ce dok god je mojid unique i napravice ti rupu. Medjutim taj problem imas i inace :)

[ MatezYU @ 12.11.2010. 14:48 ] @
Hvala ti.
Nikako da odgovorim, bio sam malo u frci sa vremenom.
Napravio sam brojac sa zakljucavanjem tabele u transakciji.
Dok prvi korisnik ne dobije broj drugi su na cekanju.
Testirao sam (napravio aplikaciju koja pokrece vise thread-ova i sve radi odlicno).
Pozdrav!