通过存储过程模拟TSQL序列


17

我需要创建一个模拟TSQL序列的存储过程。就是说,它总是在每次调用时提供递增的不同整数值。另外,如果传入一个整数,则在没有结果大于或没有下一个最大整数的情况下,应返回该值。不用说可以有多个客户端同时调用此SP。

给定具有列MetaKey varchar(max)和MeatValueLong bigInt的表MetaInfo。预期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

我的问题很简单,此存储过程是否按预期工作(将为所有调用方分配唯一的结果)?


@all:仅供参考,在此Q上生成以下代码:stackoverflow.com/q/6342732/27535
gbn

Answers:


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 2011年

@dportas:的确如此。并运行更好了:dba.stackexchange.com/q/1635/630
GBN

@dportas-SEQUENCE可以满足输入要求吗?在快速阅读该功能时,我没有看到该功能。
霍根

1

缺少以下内容

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

是的,它应该满足您的条件。一旦发生这种情况,它将创建其多个实例,随后,将为所有调用方分配唯一的结果


如果我在选择之前提交,是否有可能我会选择另一个调用保存的结果?
霍根

不确定。但是似乎你是对的。我要检查一下 谢谢。BTW +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;

OP要求允许用户传递使它复杂的值...
gbn11

@dportas-谢谢。我知道这种方法,但是由于输入参数,它在这里不起作用。
霍根

@Hogan,我修改了建议以处理输入参数。不过,大部分未经测试。
nvogel 2011年

@dportas-A调用inID为500,B调用inID为50-操作-A返回51,B返回52。要求失败。
霍根

有趣。我得到了不同的结果(在2008r2上)。您可以使用DDL发布完整的repro并声明您的构建/版本。
nvogel 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.