Domanda

Questo prenderà qualche spiegazione.Quello che ho fatto è creare uno specifico messaggio personalizzato coda in SQL Server 2005.Ho una tabella con i messaggi che contengono i timestamp per entrambi riconoscimento e di completamento.La stored procedure che i chiamanti eseguire per ottenere il messaggio successivo nella coda di stampa, inoltre, riconosce il messaggio.Finora tutto bene.Beh, se il sistema sta vivendo una quantità enorme di transazioni (in migliaia al minuto), non è possibile che un messaggio per essere riconosciuto da un'altra esecuzione della stored procedure, mentre un altro è preparato a ciò?Mi permetta di aiutare mostrando il mio codice SQL nella stored proc:

--Grab the next message id
declare @MessageId uniqueidentifier
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

--Select the entire message
...
...

Nel codice di cui sopra, non un'altra stored procedure in esecuzione allo stesso tempo di ottenere lo stesso id e il tentativo di riconoscere allo stesso tempo?Posso (o devo) implementare una sorta di blocco per impedire un'altra stored proc dal riconoscere i messaggi che un'altra stored proc è la ricerca?

Wow, qualcuno di questo anche il senso?E 'un po' difficile mettere a parole...

È stato utile?

Soluzione

Qualcosa di simile a questo

--Grab the next message id
begin tran
declare @MessageId uniqueidentifier
select top 1 @MessageId =   ActionMessageId from UnacknowledgedDemands with(holdlock, updlock);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

-- some error checking
commit tran

--Select the entire message
...
...

Altri suggerimenti

Questo mi sembra il tipo di situazione in cui OUTPUT può essere utile:

-- Acknowledge and grab the next message
declare @message table (
    -- ...your `ActionMessages` columns here...
)
update ActionMessages
set    AcknowledgedTime = getdate()
output INSERTED.* into @message
where  ActionMessageId in (select top(1) ActionMessageId from UnacknowledgedDemands)
  and  AcknowledgedTime is null

-- Use the data in @message, which will have zero or one rows assuming
-- `ActionMessageId` uniquely identifies a row (strongly implied in your question)
...
...

Ci aggiorniamo e afferrare la riga nella stessa operazione, che racconta la query optimizer esattamente quello che stiamo facendo, permettendo di scegliere la più granulare di blocco è possibile e mantenere per il più breve tempo possibile.(Anche se la colonna è prefisso INSERTED, OUTPUT è come trigger, espressa in termini di UPDATE come eliminare la riga e inserire quello nuovo).

Avrei bisogno di più informazioni circa il vostro ActionMessages e UnacknowledgedDemands tabelle (vista/funzioni con valori di tabella/qualunque cosa), per non parlare di una maggiore conoscenza di SQL Server chiusura automatica, per dire che se and AcknowledgedTime is null la clausola è necessario.È lì per difendere contro una condizione di competizione tra il sub-select e update.Sono certo che non sarebbe necessario se fossimo selezione da ActionMessages stessa (ad esempio, where AcknowledgedTime is null con un top sul update, invece di sub-select su UnacknowledgedDemands).Mi aspetto anche se è inutile, è innocuo.

Nota che OUTPUT in SQL Server 2005 e di cui sopra.Che è quello che hai detto che stavi usando, ma se la compatibilità con geriatrica SQL Server 2000 installa erano necessari, vuoi andare in un altro modo.

@Kilhoffer:

L'intero batch SQL viene analizzato prima dell'esecuzione, in modo che SQL sa che si sta andando a fare un aggiornamento della tabella e selezionare da.

Edit:Inoltre, SQL non necessariamente bloccare l'intero tavolo, potrebbe bloccare le righe necessarie.Vedere qui per una panoramica di blocco in SQL server.

Invece di esplicita di chiusura, che spesso è sfociata in SQL Server per maggiore granularità di quanto desiderato, perché non provare questo approccio:

declare @MessageId uniqueidentifier
select top 1 @MessageId = ActionMessageId from UnacknowledgedDemands

update ActionMessages
  set AcknowledgedTime = getdate()
  where ActionMessageId = @MessageId and AcknowledgedTime is null

if @@rowcount > 0
  /* acknoweldge succeeded */
else
  /* concurrent query acknowledged message before us,
     go back and try another one */

Meno si blocca, il più alto livello di concorrenza che si hanno.

Dovrebbe davvero essere l'elaborazione di cose una per una?Non basta SQL Server riconosce tutti i messaggi non riconosciuti con la data di oggi e di restituirli?(tutti anche in una transazione di corso)

Leggi di più su SQL Server Selezionare Blocco qui e qui.SQL Server è in grado di richiamare un blocco di tabella su seleziona.Non succederà nulla al tavolo durante la transazione.Quando la transazione è completa, eventuali inserimenti o aggiornamenti poi si risolvono da soli.

Si desidera racchiudere il codice in una transazione, quindi SQL server consente di gestire chiusura appropriato le righe o le tabelle.

begin transaction

--Grab the next message id
declare @MessageId uniqueidentifier
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

commit transaction

--Select the entire message
...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top