2011-11-01 19 views
5

voglio:SQL Select righe da una tabella e aggiornare le stesse righe

  1. Select N righe da una tabella per l'elaborazione in cui flag = 0
  2. fare un certo lavoro su una seconda tabella con valori da queste N righe
  3. aggiornare queste N righe e impostare flag = 1

ho processi paralleli che fanno questo stesso lavoro insieme, e voglio garantire che tutti al lavoro sulle righe uniche. Come posso assicurarlo?

risposta

5

Suppongo che tu stia eseguendo su SQL Server (a causa del tag), in caso contrario la mia risposta non è applicabile. Il blocco da solo non è sufficiente. Se si utilizza il blocco del record del database, il server SqL bloccherà altri processi che tentano di accedere alla riga bloccata e, in effetti, gestirà solo una riga alla volta. La soluzione per voi è combinare il blocco delle righe con l'hint READPAST in modo che le righe bloccate da qualcun altro vengano saltate. Ecco ciò che ogni processo deve fare:

  1. selezionare riga successiva sbloccato per l'elaborazione e bloccarlo
  2. fare il lavoro
  3. aggiornamento della transazione fila e alla fine

select top 1 id, ... from TheTable with (updlock, readpast) where flag = 0

//do the work now

update TheTable set flag = 1 where id=<previously retrieved id>

La cosa bella è che l'operazione di selezionare la successiva riga sbloccata e bloccarla è atomica, così garantisce che nessun altro sarà in grado di selezionare la stessa riga.

+0

Il suggerimento READPAST fa il trucco, un buon articolo http://www.mssqltips.com/sqlservertip/1257/processing-data-queues-in-sql-server-with-readpast-and-updlock/ – newbie

+0

Con SQL 2008 , è possibile utilizzare la clausola OUTPUT con l'avviso READPAST nella query per combinare l'operazione di coda in una singola istruzione.http: //www.sqlservercentral.com/articles/Queue+processing/69653/ – newbie

+0

@newbie Sì, è possibile utilizzare output per bloccare e recuperare i messaggi e contrassegnarli elaborati in una singola query. Ma ho confrontato le prestazioni per l'elaborazione di singoli messaggi e non c'è alcun guadagno rispetto a due query (selezionare prima e poi aggiornare). In realtà il throughput multi-thread era leggermente inferiore quando si utilizzava la query OUTPUT. Forse nell'elaborazione batch la clausola Output sarebbe più veloce, ma per i singoli messaggi non lo è. – nightwatch

0

Un modo è che un programma master distribuisca i segmenti ai thread secondari.

Un altro modo è bloccare la tabella, ottenere le righe CEIL(N/#processes) dove flag = 0, aggiornare il flag su 2, quindi rilasciare il blocco. Quindi il processo successivo continuerà da quando ha ottenuto il blocco, e poiché flag = 2 non otterrà quelle righe.

Esistono due modi per bloccare la tabella: è possibile bloccare l'intera operazione oppure selezionare SELECT ... FOR UPDATE con un limite (per non ottenere troppe righe). Vedi: SELECT FOR UPDATE with SQL Server

Ancora meglio dell'impostazione del flag su 2 viene impostato il flag su process_id. Quindi tutto ciò che devi fare è aggiornare tutte le righe per distribuire i numeri, quindi lasciare che il processo vada a buon fine, ognuno controllando solo le proprie righe.

Problemi correlati