Gå til innhold

(ms)sql: Select / update racecontition


Anbefalte innlegg

Jeg trenger å få utført følgende to query samtidig:

Select * from myTable where status=0

Update myTable set status=1 where status=0

 

Altså, jeg trenger å få hentet ut radene som endres, samtidig som de endres. Risikoen her er at en annen prosess kan finne på å legge til nye rader med status=0 mellom select og update. Hvordan kan jeg skrive query slik at det er garantert at det er de samme radene som returneres av select og oppdateres av update?

Lenke til kommentar
Videoannonse
Annonse

Quantum har selvsagt helt rett, og det er vanskelig å si særlig mer uten å vite litt mer om hva du egentlig gjør.

 

Hvis det er mange rader, så er gjerne den løsningen best. Hvis det er få rader du skal oppdatere, så kan du kanskje endre WHERE i UPDATE til å gå mot ID på datene fra den første spørringen.

 

Da påvirker du bare radene du hentet ut, og slipper å endre isolation level.

Lenke til kommentar

Å bruke id'ene fra den første spørringen er ikke så dumt, men det kan være begrensninger i implementasjonen om man bruker update blablabla where id in (1,2,3,4,5 ....) - altså begrenset hvor mange id'er man kan putte i in-klausulen.

 

Et annet alternativ kan være "select .... for update"; se f.eks. her http://stackoverflow.com/questions/10935850/when-to-use-select-for-update.

 

Som terjeelde sier - det blir et spørsmål om hva du egentlig gjør. Hva er f.eks. hensikten med select først?

Lenke til kommentar

SELECT FOR UPDATE låser radene du SELECTer, men gjør ikke noe for ny-innsatte rader.

 

Hvis radene kan slettes mellom SELECT og UPDATE, så må du kombinere min tanke om å bruke id, med quantums tanke om FOR UPDATE.

 

Tenker det burde være en grei løsning om antall rader ikke skaper problemer, men igjen, vanskelig å si mer uten å vite mer.

Lenke til kommentar

Databasen er en slags logg som stadig får nye rader fra en prosess (ca 500 om dagen)

Jeg har lagt til en ekstra kolonne med status default 0, slik at alle rader prosessen skriver får status 0.

 

Planen er at jeg skal skrive et slags loganalyseverktøy som kjører med jevne mellomrom, leser ut alle (evt limit X) som har status=0, endrer status på disse til 1, og gjør noe med logmeldingene (f.eks sende mail om det er mange av en type)

 

Tanken med status feltet er å holde styr på hvilke rader analyseverktøyet har behandlet og ikke. Bruk av timestamp eller Id kan ikke brukes fordi prosessen som skriver radene skriver noen typer direkte, og andre med en forsinkelse.

 

Hvilken metode høres ut som er mest fornuftig for dette?

Lenke til kommentar

Iom. at ikke log'entryene nødvendigvis skrives umiddelbart så vil du få «overlapp» i analyse-batchene, det kan du ikke unngå vha. isolationlevels og «for update»., medmindre du vet max. forsinkelse og sørger for at log-analysatoren alltid ligger på «etterskudd» større enn max forsinkelse.

 

For meg ser det ut som det eneste problemet ditt er at du tenker select og update i feil rekkefølge, hva med

update logtable set status = status +1; -- status initielt = 0;
select * from logtable where stautus = 1;

(du kan gjøre dette mer effektivt men logisk sett blir det ekvivalent). Dette blir ikke så veldig annerledes enn å bruke timestamp eller id, men du må nesten forklare hva som gjør at dette ikke vil funke for deg. (jadda, er muligens litt treig i nøtta ...)

 

Edit: Spørsmålet er egentlig om det er nok å garantere at analyseverktøyet ikke teller den samme pannekaka to ganger, eller om det også må garanteres at det ikke er overlapp på tidsintervallene over entries som hver enkelt analyse-runde behandler.

Endret av quantum
Lenke til kommentar

select før update medfører at man kan risikere å oppdatere flere rader enn man hadde med i select

update før select medfører at man får med rader som allerede er behandlet i tidligere.

update - select - update bør kunne fungere.

update tabell set status = 1 where status = 0
select * from tabell where status=1
update tabell set status = 2 where status = 1

Da betyr status=0 ubehandlet, status=1 utvalgt for behandling, status=2 innlest av behandlingsprosess

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...