Эмулировать последовательность TSQL с помощью хранимой процедуры

17

У меня есть требование создать хранимую процедуру, которая эмулирует последовательность TSQL. То есть он всегда дает возрастающее целочисленное значение при каждом вызове. Кроме того, если передается целое число, оно должно возвращать это значение, если никогда не было результата, большего или следующего доступного целого числа. Само собой разумеется, что могут быть несколько клиентов, вызывающих этот SP одновременно.

Дана таблица MetaInfo со столбцами MetaKey varchar (max) и MeatValueLong bigInt. Ожидается, что строка с MetaKey 'Internal-ID-Last' будет содержать последнее присвоенное наибольшее значение. Я создал следующую хранимую процедуру:

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

У меня простой вопрос, работает ли эта хранимая процедура как ожидалось (всем абонентам будет присвоен уникальный результат)?

Hogan
источник
@all: FYI, порожденный этим Q на SO: stackoverflow.com/q/6342732/27535
gbn

Ответы:

8

Я посмотрел и MS предлагает решение без замков

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

Это простое обновление без подсказок о блокировке, но говорят, что оно блокирует / блокирует блокировку.

Ничего особенного в этом тоже нет.

Я был бы склонен добавить UPDLOCK к вашему ROWLOCK (согласно «таблице как очереди» (SO), но без READPAST). Это увеличит изоляцию в случае начала чтения второго процесса.

Однако тот факт, что все ваши процессы хотят читать / записывать одну и ту же строку, заставляет меня задуматься. READPAST позволяет безопасный параллелизм, но в этом случае он бесполезен.

Примечание: вы можете использовать предложение OUTPUT вместо второго выбора, тогда вам не нужна транзакция.

НТН ...

ГБН
источник
1
Ты подтолкнул меня на это. Обратите внимание, что SQL Server 2011 включает в себя функциональность SEQUENCE, поэтому требование изобретать свое собственное решение должно скоро исчезнуть (не раньше).
nvogel
@dportas: действительно. И работает лучше тоже: dba.stackexchange.com/q/1635/630
gbn
@dportas - может ли SEQUENCE учитывать требования ввода? В моем кратком прочтении этой функции я не увидел эту функциональность.
Хоган
1

Следующая вещь отсутствует

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

Да, это должно соответствовать вашему состоянию. Как только такие ситуации возникают в транзакциях, он создает несколько экземпляров, и впоследствии всем вызывающим будет присвоен уникальный результат.

Панкай
источник
Если я сделаю коммит до выбора, не будет ли возможности выбрать результат, сохраненный другим вызовом?
Хоган
Не уверен в этом. Но, похоже, ты прав. Мне нужно проверить. Благодарю. Кстати +1 для, хороший вопрос ...
0

Более масштабируемое решение, которое не требует сериализации, таково:

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;
nvogel
источник
У OP есть требование разрешать пользователям передавать значение, которое усложняет его ...
gbn
@dportas - Спасибо. Я знал об этом подходе, но он не работает здесь из-за входного параметра.
Хоган
@ Хоган, я изменил свое предложение для обработки входного параметра. Это в основном не проверено, хотя.
nvogel
@dportas - A вызывается с inID 500, B вызывается с inID 50 - действие - A возвращается с 51, B с 52. Требование не выполнено.
Хоган
Интересный. Я получаю разные результаты (на 2008r2). Можете ли вы опубликовать полную версию с DDL и указать свою сборку / версию.
nvogel