Emulare una sequenza TSQL tramite una stored procedure


17

Ho un requisito per creare una procedura memorizzata che emula una sequenza TSQL. Cioè dà sempre un valore intero distinto crescente su ogni chiamata. Inoltre, se viene passato un numero intero, dovrebbe restituire quel valore se non è mai stato ottenuto un risultato maggiore o il successivo intero più alto disponibile. Inutile dire che possono esserci più client che chiamano questo SP contemporaneamente.

Data una tabella MetaInfo con colonne MetaKey varchar (max) e MeatValueLong bigInt. Si prevede che la riga con il MetaKey di "Internal-ID-Last" conterrà l'ultimo valore più alto assegnato. Ho creato la seguente procedura memorizzata:

CREATE PROCEDURE [dbo].[uspGetNextID]
(
  @inID bigInt 
)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRANSACTION

    UPDATE MetaInfo WITH (ROWLOCK) 
      SET MetaValueLong = CASE 
                            WHEN ISNULL(MetaValueLong,0) > @inID THEN MetaValueLong+1 
                            ELSE @inID+1
                          END 
    WHERE MetaKey = 'Internal-ID-Last'

    SELECT MetaValueLong 
    FROM MetaInfo
    WHERE MetaKey = 'Internal-ID-Last'

    COMMIT TRANSACTION 

END

La mia domanda è semplicemente: questa procedura memorizzata funziona come previsto (a tutti i chiamanti verrà assegnato un risultato unico)?


@all: FYI, generato da questa Q su SO: stackoverflow.com/q/6342732/27535
gbn

Risposte:


8

Ho dato un'occhiata e gli stessi MS offrono una soluzione senza serrature

http://blogs.msdn.com/b/sqlcat/archive/2006/04/10/sql-server-sequence-number.aspx

Questo è un semplice aggiornamento senza suggerimenti di blocco, ma dicono che blocca / deadlock.

Non c'è molto da dire su questo.

Sarei propenso ad aggiungere UPDLOCK al tuo ROWLOCK (come da "tabella come coda" (SO) ma senza READPAST). Ciò aumenterà l'isolamento nel caso in cui un secondo processo inizi a leggere.

Tuttavia, il fatto che tutti i tuoi processi vogliano leggere / scrivere sulla stessa riga mi fa pensare a me stesso. READPAST consente una concorrenza sicura ma in questo caso è inutile.

Nota: è possibile utilizzare la clausola OUTPUT anziché una seconda selezione, quindi non è necessaria la transazione.

HTH ...


1
Mi hai battuto sul tempo. Si noti che SQL Server 2011 include la funzionalità SEQUENCE, pertanto il requisito di inventare il proprio dovrebbe scomparire presto (non prima del tempo).
nvogel

@dportas: davvero. E funziona anche meglio: dba.stackexchange.com/q/1635/630
gbn

@dportas - SEQUENCE può consentire requisiti di input? Nella mia rapida lettura della funzione non ho visto quella funzionalità.
Hogan,

1

Mancano le seguenti cose

1. SET XACT_ABORT
2. Exception Handling (Try Catch)

Sì, dovrebbe soddisfare le tue condizioni. Una volta che tali situazioni arrivano nelle transazioni, crea le sue molteplici istanze e, successivamente, a tutti i chiamanti verrà assegnato un risultato unico


Se mi impegno prima che la selezione non sia possibile, selezionerò il risultato salvato da una chiamata diversa?
Hogan,

Non ne sono sicuro. Ma sembra che tu abbia ragione. Ho bisogno di controllare. Grazie. A proposito +1, buona domanda ...

0

Una soluzione più scalabile che non richiede la serializzazione è questa:

CREATE PROCEDURE [dbo].[uspGetNextID]
(
  @inID BIGINT OUT
)
AS
      SET NOCOUNT ON
      SET IDENTITY_INSERT SequenceTable ON;
      INSERT INTO SequenceTable (id) VALUES (@inID);
      SET IDENTITY_INSERT SequenceTable OFF;
      INSERT INTO SequenceTable DEFAULT VALUES;
      DELETE FROM SequenceTable WITH (READPAST);
      SET @inID = SCOPE_IDENTITY();
RETURN;

L'OP ha l'obbligo di consentire agli utenti di trasmettere un valore che lo complica ...
gbn

@dportas - Grazie. Ero a conoscenza di questo approccio, ma non funziona qui a causa del parametro di input.
Hogan,

@Hogan, ho modificato il mio suggerimento per gestire il parametro di input. È per lo più non testato però.
nvogel

@dportas - A chiamato con inID di 500, B chiamato con inID di 50 - azione - A restituisce con 51, B con 52. Requisito non riuscito.
Hogan,

Interessante. Ottengo risultati diversi (su 2008r2). Puoi pubblicare la riproduzione completa con DDL e dichiarare la tua build / versione.
nvogel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.