/ Forside / Teknologi / Udvikling / SQL / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
SQL
#NavnPoint
pmbruun 1704
niller 962
fehaar 730
Interkril.. 701
ellebye 510
pawel 510
rpje 405
pete 350
gibson 320
10  smorch 260
[SQL2k] Kapløb
Fra : Torben Frandsen


Dato : 24-03-04 10:52

Hej

Jeg har en tabel hvor en applikation inserter en række en gang i mellem. En
anden applikation poller med jævne mellemrum tabellen med en sp for at se om
der skulle være kommet noget nyt. Denne applikation skal køre i flere
instanser, og derfor er det vigtigt at to eller flere instanser ikke kommer
til at tage den samme række. Foreløbig ser min sp i princippet sådan ud:

IF EXISTS(
SELECT ID
FROM Job
WHERE Taken = 0)

BEGIN
SELECT TOP 1 @GUID = ID FROM Job WHERE Taken = 0
UPDATE Job SET Taken = 1 WHERE ID = @GUID
RETURN 1
END
ELSE
RETURN 0

Spørgsmålet er, om jeg kan være sikker på om caller2 kan nå at evaluere
(Taken = 0) i det splitsekund der vel må gå før caller1 kan sige SET Taken =
1.

Torben



 
 
Torben Frandsen (24-03-2004)
Kommentar
Fra : Torben Frandsen


Dato : 24-03-04 11:08

Torben Frandsen wrote:

> Spørgsmålet er, om jeg kan være sikker på om caller2 kan nå at
> evaluere (Taken = 0) i det splitsekund der vel må gå før caller1 kan
> sige SET Taken = 1.

Nej det er ej. Spørgsmålet er, om jeg kan være sikker på at caller 2 /ikke/
kan nå at evaluere (Taken = 0) til true i det splitsekund osv.

Torben



Kristian Damm Jensen (24-03-2004)
Kommentar
Fra : Kristian Damm Jensen


Dato : 24-03-04 12:09

Torben Frandsen wrote:
> Torben Frandsen wrote:
>
>> Spørgsmålet er, om jeg kan være sikker på om caller2 kan nå at
>> evaluere (Taken = 0) i det splitsekund der vel må gå før caller1 kan
>> sige SET Taken = 1.
>
> Nej det er ej. Spørgsmålet er, om jeg kan være sikker på at caller 2
> /ikke/ kan nå at evaluere (Taken = 0) til true i det splitsekund osv.

Det kan du ikke. Læs op på transaktionsstyring.


--
Kristian Damm Jensen damm (at) ofir (dot) dk
I hate to advocate drugs, alcohol, violence, or insanity to anyone, but
they've always worked for me. -- Hunter S. Thompson


Torben Frandsen (24-03-2004)
Kommentar
Fra : Torben Frandsen


Dato : 24-03-04 16:01

Kristian Damm Jensen wrote:
> Torben Frandsen wrote:
>> Torben Frandsen wrote:
>>
>>> Spørgsmålet er, om jeg kan være sikker på om caller2 kan nå at
>>> evaluere (Taken = 0) i det splitsekund der vel må gå før caller1 kan
>>> sige SET Taken = 1.
>>
>> Nej det er ej. Spørgsmålet er, om jeg kan være sikker på at caller 2
>> /ikke/ kan nå at evaluere (Taken = 0) til true i det splitsekund osv.
>
> Det kan du ikke. Læs op på transaktionsstyring.

Takker. Hvis de to statements (men ikke IF EXISTS) sker mellem BEGIN TRAN og
COMMIT, og hvis SELECT gøres med et READPAST-hint, så nærmer vi os vel noget
brugbart?

Torben



Kristian Damm Jensen (24-03-2004)
Kommentar
Fra : Kristian Damm Jensen


Dato : 24-03-04 21:52

Torben Frandsen wrote:
> Kristian Damm Jensen wrote:
>> Torben Frandsen wrote:
>>> Torben Frandsen wrote:
>>>
>>>> Spørgsmålet er, om jeg kan være sikker på om caller2 kan nå at
>>>> evaluere (Taken = 0) i det splitsekund der vel må gå før caller1
>>>> kan sige SET Taken = 1.
>>>
>>> Nej det er ej. Spørgsmålet er, om jeg kan være sikker på at caller 2
>>> /ikke/ kan nå at evaluere (Taken = 0) til true i det splitsekund
>>> osv.
>>
>> Det kan du ikke. Læs op på transaktionsstyring.
>
> Takker. Hvis de to statements (men ikke IF EXISTS) sker mellem BEGIN
> TRAN og COMMIT, og hvis SELECT gøres med et READPAST-hint, så nærmer
> vi os vel noget brugbart?

Jeg er ikke ekspert i MsSQL så jeg aner ikke hvad READPAST gør. Men det
øvrige lyder rimeligt. Tilføj, at din fejlbehandling, hvis du har en sådan
skal benytte rollback tran. Og hvis du så vil være på den sikre side laver
du en trigger, der forhindrer at man taken fra 1 til 1!


--
Kristian Damm Jensen damm (at) ofir (dot) dk
....See their swords? They glow blue in the presence of lawyers. --
Terry Pratchett


Jacob Buus Smidt (25-03-2004)
Kommentar
Fra : Jacob Buus Smidt


Dato : 25-03-04 19:55


"Torben Frandsen" <torben@rem.airsupport.dk> skrev i en meddelelse
news:40615a2e$0$217$edfadb0f@dread16.news.tele.dk...
>
> IF EXISTS(
> SELECT ID
> FROM Job
> WHERE Taken = 0)
>
> BEGIN
> SELECT TOP 1 @GUID = ID FROM Job WHERE Taken = 0
> UPDATE Job SET Taken = 1 WHERE ID = @GUID
> RETURN 1
> END
> ELSE
> RETURN 0
>

En alternativ metode kunne være følgende:

/* Marker "ledige jobs" */
UPDATE Job
SET Taken = @@SPID
WHERE Taken = 0

/* Hvis nogen blev markeret */
IF @@ROWCOUNT > 0
BEGIN

/* Find de netop markerede
SELECT *
FROM Job
WHERE Taken = @@SPID

/* Gør det, du havde tænkt dig at gøre med posterne... */

RETURN 1
END
ELSE
RETURN 0


I øvrigt skal du i ovenstående finde en måde at markere de poster, der
allerede har været valgt, idet "SELECT *..."-sætningen jo udvælger alle
poster, som den pågældende proces tidligere har "taget ejerskab" af. Måske,
du skulle erstatte @@SPID med din @GUID fra før, så er du på den sikre side.

Ideen er, at du finder og markerer i samme operation, hvorved du undgår at
skulle opfinde din egen semafor / kritisk region via. transaktionsstyring.

Det er muligt, at du skal finde en anden variant på samme idegrundlag, som
passer til netop din situation.



--

Hilsen Jacob



Torben Frandsen (26-03-2004)
Kommentar
Fra : Torben Frandsen


Dato : 26-03-04 09:57

Jacob Buus Smidt wrote:

> Ideen er, at du finder og markerer i samme operation, hvorved du
> undgår at skulle opfinde din egen semafor / kritisk region via.
> transaktionsstyring.

Din løsning skal helt klart have et par point for elegance. Hvad jeg ikke
skrev var, at grunden til at der ville være flere instanser af den kaldende
applikation, er at der skal være en simpel load balancing. Umiddelbart ville
man med din løsning kunne risikere at kalder1 får en helt masse jobs og
kalder2, som kommer forbi en jiffy senere får nul.

Det kunne man selvfølgelig fixe ved at skrive UPDATE TOP 1 (...) (Hwa? Ka
man æ? Nå men så en IN-klausul da.)

Nu spekulerer jeg bare på, hvad performer bedst, en samlet transaktion eller
din metode med en IN(SELECT TOP (...))-klausul på?

Torben



Jacob Buus Smidt (26-03-2004)
Kommentar
Fra : Jacob Buus Smidt


Dato : 26-03-04 18:24

>
> Din løsning skal helt klart have et par point for elegance. Hvad jeg ikke
> skrev var, at grunden til at der ville være flere instanser af den
kaldende
> applikation, er at der skal være en simpel load balancing. Umiddelbart
ville
> man med din løsning kunne risikere at kalder1 får en helt masse jobs og
> kalder2, som kommer forbi en jiffy senere får nul.
>
> Det kunne man selvfølgelig fixe ved at skrive UPDATE TOP 1 (...) (Hwa? Ka
> man æ? Nå men så en IN-klausul da.)
>



Ok, men så lad os se, hvordan det ser ud:

DECLARE @myid uniqueidentifier
SET @myid = NEWID()

/* Marker et ledigt job */
UPDATE Job
SET Taken = @myid
WHERE ID = (SELECT TOP 1 J.ID FROM Job J WHERE J.Taken IS NULL)

/* Hvis noget blev markeret */
IF @@ROWCOUNT > 0
BEGIN

/* Find det netop markerede
SELECT *
FROM Job
WHERE Taken = @myid

/* Gør det, du havde tænkt dig at gøre med posten... */

RETURN 1
END
ELSE
RETURN 0


> Nu spekulerer jeg bare på, hvad performer bedst, en samlet transaktion
eller
> din metode med en IN(SELECT TOP (...))-klausul på?
>

Jeg tror, at ovenstående er mindst ligeså optimalt, som din endelige
løsning, som du postede i en anden tråd. Især, hvis du har mange samtidige
operationer i job-tabellen, da SQL servers proces-scheduler ikke kan stille
noget op over for dine explicitte låse. Husk på, at "(SELECT TOP 1 J.ID FROM
Job J WHERE J.Taken = 0)" kun evalueres én gang.


Hilsen Jacob



Torben Frandsen (30-03-2004)
Kommentar
Fra : Torben Frandsen


Dato : 30-03-04 12:59

Jacob Buus Smidt wrote:

> Jeg tror, at ovenstående er mindst ligeså optimalt, som din endelige
> løsning, som du postede i en anden tråd. Især, hvis du har mange
> samtidige operationer i job-tabellen, da SQL servers proces-scheduler
> ikke kan stille noget op over for dine explicitte låse. Husk på, at
> "(SELECT TOP 1 J.ID FROM Job J WHERE J.Taken = 0)" kun evalueres én
> gang.

Nu prøvede jeg lige at hakke det ind i Query Analyzer og lave en Estimated
Execution Plan. Scoren blev:
Dig: 57,14%
Mig: 42,86%

Jeg er ikke i tvivl om at det tipper i din favør, når der ad åre kommer
mange samtidige operationer. Men hvor meget? Lige nu er jeg !(nysgerrig nok
&& nervøs nok && ledig nok) til at generere et gennemtestet svar.

Torben



Stig Johansen (29-03-2004)
Kommentar
Fra : Stig Johansen


Dato : 29-03-04 04:09

Torben Frandsen wrote:

> Hvad jeg ikke
> skrev var, at grunden til at der ville være flere instanser af den
> kaldende applikation, er at der skal være en simpel load balancing.
[snip]
> Nu spekulerer jeg bare på, hvad performer bedst ...

Hvis du er nervøs for performance(systemet), skal du slet ikke lave det på
den måde.
Kan du i forhold til din OP uddybe:
....inserter en række en gang i mellem. -> Hvor tit?
....poller med jævne mellemrum -> Hvor tit?

--
Med venlig hilsen
Stig Johansen

Torben Frandsen (30-03-2004)
Kommentar
Fra : Torben Frandsen


Dato : 30-03-04 10:57

Stig Johansen wrote:

> Hvis du er nervøs for performance(systemet), skal du slet ikke lave
> det på den måde.

Nervøs er måske så meget sagt. Men serveren løser mange opgaver, og med
tanke på mange-bække-små-princippet bør man nok forsøge at undgå indlysende
performance-spild.

> Kan du i forhold til din OP uddybe:
> ...inserter en række en gang i mellem. -> Hvor tit?

Det ved jeg først når systemet går i produktion. Men forventeligt omkring
500 gange i døgnet.

Det skal måske med at et af felterne i tabellen er af typen 'image' og kan
fylde op til 2MB, og det er den eksterne behandling af dette, der tager tid
(op til 20 minutter.) Når jeg siger load balancing, er det altså denne
behandling der skal fordeles over flere maskiner.

> ...poller med jævne mellemrum -> Hvor tit?

5s, hvilket kan accepteres fordi klienterne tilgår systemet fra et asynkront
miljø. Brugernes indtryk af responsiveness er alligevel rent snyd.

Torben



Stig Johansen (05-04-2004)
Kommentar
Fra : Stig Johansen


Dato : 05-04-04 04:27

Torben Frandsen wrote:

> Stig Johansen wrote:
>
>> Hvis du er nervøs for performance(systemet), skal du slet ikke lave
>> det på den måde.
>
> Nervøs er måske så meget sagt. Men serveren løser mange opgaver, og med
> tanke på mange-bække-små-princippet bør man nok forsøge at undgå
> indlysende performance-spild.

Enig, uanset hvad, er det altid en god ide, at spare mest muligt på
ressourcer.

>> Kan du i forhold til din OP uddybe:
>> ...inserter en række en gang i mellem. -> Hvor tit?
>
> Det ved jeg først når systemet går i produktion. Men forventeligt omkring
> 500 gange i døgnet.

Det lyder jo ikke af særligt meget, ca 20 i timen.

> Det skal måske med at et af felterne i tabellen er af typen 'image' og kan
> fylde op til 2MB, og det er den eksterne behandling af dette, der tager
> tid (op til 20 minutter.) Når jeg siger load balancing, er det altså denne
> behandling der skal fordeles over flere maskiner.

Det lyder heller ikke af meget, men hov - 20 minutters behandlingstid, 20 i
timen, det må jo give hele 7 maskiner til din externe behandling, er det
korrekt?

>
>> ...poller med jævne mellemrum -> Hvor tit?
>
> 5s, hvilket kan accepteres fordi klienterne tilgår systemet fra et
> asynkront miljø. Brugernes indtryk af responsiveness er alligevel rent
> snyd.

Det lyder også acceptabelt, men hvis der er 7 maskiner, er det mere end 1
pr. sek.

Det gan godt være, jeg har misforstået det, men for mig ser dit setup noget
ala:

(Bruger)Data -> SQLServer -> Data behandles på Extern server(e) -> Data
opdateres SQLServer -> (Bruger)Data færdig.
Er det noget i den stil, du har gang i?

Hvis det er sådan noget, er det nok smartere at lave en trigger på insert,
der kalder en xp, der håndterer loadbalancing med noget broadcast.

--
Med venlig hilsen
Stig Johansen

Torben Frandsen (13-04-2004)
Kommentar
Fra : Torben Frandsen


Dato : 13-04-04 12:01

Stig Johansen wrote:

> Det lyder heller ikke af meget, men hov - 20 minutters
> behandlingstid, 20 i timen, det må jo give hele 7 maskiner til din
> externe behandling, er det korrekt?

Jaeh, eller i hvert fald 7 eksterne processer.

> Det lyder også acceptabelt, men hvis der er 7 maskiner, er det mere
> end 1 pr. sek.

Det kan vi vist ikke blive uenige om :)

> Det gan godt være, jeg har misforstået det, men for mig ser dit setup
> noget ala:
>
> (Bruger)Data -> SQLServer -> Data behandles på Extern server(e) ->
> Data opdateres SQLServer -> (Bruger)Data færdig.
> Er det noget i den stil, du har gang i?

Jeps, og så er der nogle side effects undervejs.

> Hvis det er sådan noget, er det nok smartere at lave en trigger på
> insert, der kalder en xp, der håndterer loadbalancing med noget
> broadcast.

Det har du muligvis ret i, men så kommer jeg vist for langt ud i uncharted
territory :)

Torben



Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408925
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste