Emule una secuencia TSQL a través de un procedimiento almacenado


17

Tengo el requisito de crear un procedimiento almacenado que emule una secuencia TSQL. Es decir, siempre da un valor entero distinto y creciente en cada llamada. Además, si se pasa un entero, debe devolver ese valor si nunca ha habido un resultado mayor o el siguiente entero más alto disponible. No hace falta decir que puede haber varios clientes llamando a este SP al mismo tiempo.

Dada una tabla MetaInfo con columnas MetaKey varchar (max) y MeatValueLong bigInt. Se espera que la fila con la MetaKey de 'Internal-ID-Last' contenga el último valor más alto asignado. Creé el siguiente procedimiento almacenado:

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

Mi pregunta es simplemente: ¿funciona este procedimiento almacenado como se esperaba (a todas las personas que llamen se les asignará un resultado único)?


@todos: FYI, generado por esta Q en SO: stackoverflow.com/q/6342732/27535
— gbn

Respuestas:


8

He echado un vistazo y los propios MS ofrecen una solución sin bloqueos

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

Esta es una actualización simple sin sugerencias de bloqueo, pero dicen que bloquea / bloquea.

No hay mucho en SO sobre esto tampoco.

Me inclinaría a agregar UPDLOCK a su ROWLOCK (según "table as a queue" (SO) pero sin READPAST). Esto aumentará el aislamiento en caso de que un segundo proceso comience a leer.

Sin embargo, el hecho de que todos sus procesos quieran leer / escribir la misma fila me hace dudar de mí mismo. READPAST permite concurrencia segura, pero en este caso es inútil.

Nota: puede usar la cláusula OUTPUT en lugar de una segunda selección, entonces no necesita la transacción.

HTH ...


1
Me ganaste a eso. Tenga en cuenta que SQL Server 2011 incluye la funcionalidad SECUENCIA, por lo que el requisito de inventar el suyo debe desaparecer pronto (no antes de tiempo).
— nvogel

@dportas: de hecho. Y también funciona mejor: dba.stackexchange.com/q/1635/630
— gbn

@dportas: ¿la SECUENCIA puede permitir el requisito de entrada? En mi lectura rápida de la función, no vi esa funcionalidad.
— Hogan

1

Falta lo siguiente

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

Sí, debe cumplir con su condición. Una vez que tales situaciones surgen en las transacciones, crea sus múltiples instancias y, posteriormente, a todos los que llaman se les asignará un resultado único


Si me comprometo antes de la selección, ¿no existe la posibilidad de seleccionar el resultado guardado por una llamada diferente?
— Hogan

No estoy seguro de eso. Pero parece que tienes razón. Necesito verificarlo. Gracias. Por cierto +1 para, buena pregunta ...

0

Una solución más escalable que no requiere serialización es esta:

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;

OP tiene un requisito para permitir a los usuarios pasar de un valor que lo complica ...
— gbn

@dportas - Gracias. Conocía este enfoque, pero no funciona aquí debido al parámetro de entrada.
— Hogan

@Hogan, he modificado mi sugerencia para manejar el parámetro de entrada. Sin embargo, en su mayoría no ha sido probado.
— nvogel

@dportas - A llamado con inID de 500, B llamado con inID de 50 - acción - A regresa con 51, B con 52. Fallo del requisito.
— Hogan

Interesante. Obtengo resultados diferentes (en 2008r2). ¿Puede publicar la reproducción completa con DDL y establecer su compilación / versión.
— nvogel
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.