Identity列的替代方案

时间:2012-10-19 07:44:33

标签: sql-server-2008 identity-column

我们有一个带有标识列(OrderID)的Orders表,但我们的订单号由OrderType(2个字符),OrderYear(2个字符)和OrderID(6个字符)组成,总共10个字符(即XX12123456)。 此计数器有限制:我们可以作为OrderID到达身份999999。下一个订单将由7个字符组成ID。显然,我们不能重复订单ID。

因此我们创建了一个预先填充了OrderID和OrderYear的表(例如,从100000到999999,订单年从12到16):这个存储过程以SERIALIZABLE隔离级别开始交易,不使用第一个订单ID,将其更新为已使用并提交事务。

作为我们的订单表,我担心执行订单ID计算存储过程或重复订单时出现死锁。

我将使用一个创建多个并发线程的控制台应用程序来测试它,并尝试提取模拟生产负载的orderid。

怀疑是:

  • 是否存在另一种安全模拟标识列的方法?
  • 可以考虑使用触发器吗?
  • 可以考虑不同的隔离级别吗?
  • 其他想法? :d

谢谢!

[编辑]

在谷歌搜索并阅读了大量MSDN文档之后,我发现了许多示例,展示了如何直接从SP管理错误和处理错误以及接受某种类型的自动回复,如下所示:

CREATE PROCEDURE [dbo]。[sp_Ordine_GetOrderID]

@AnnoOrdine AS NVARCHAR(2)= NULL OUTPUT, @IdOrdine AS INT = NULL OUTPUT

AS

设置NOCOUNT

DECLARE @retry AS INT SET @retry = 2

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

WHILE(@retry> 0) 开始     开始尝试

    BEGIN TRANSACTION OrderID   

    SELECT TOP 1 @AnnoOrdine = AnnoOrdine, @IdOrdine = IdOrdine
    FROM ORDINI_PROGRESSIVI --WITH (ROWLOCK)
    WHERE Attivo = 1
    --ORDER BY AnnoOrdine ASC, IDOrdine ASC 

    UPDATE ORDINI_PROGRESSIVI WITH (UPDLOCK)
    SET Attivo = 0
    WHERE AnnoOrdine = @AnnoOrdine AND IdOrdine = @IdOrdine

    IF ISNULL(@IdOrdine, '') = '' OR ISNULL(@AnnoOrdine,'') = ''
    BEGIN
        RAISERROR('Deadlock', 1, 1205)
    END

    SET @retry = 0

    COMMIT TRANSACTION OrderID  

    SELECT @AnnoOrdine AS AnnoOrdine, @IdOrdine AS IdOrdine 

END TRY
BEGIN CATCH

    IF (ERROR_NUMBER() = 1205)
        SET @retry = @retry - 1;
    ELSE
        SET @retry = -1;

    IF XACT_STATE() <> 0
        ROLLBACK TRANSACTION;       

END CATCH

END

这种方法减少了死锁(根本不存在),但有时候我得到了EMPTY输出参数。 使用30个当代线程进行测试(因此,30个客户流程在同一时刻插入订单)

这是一个带有查询持续时间的调试日志,以毫秒为单位:http://nopaste.info/285f558758.html

足够强大的生产?

1 个答案:

答案 0 :(得分:0)

如果您确实发现当前的解决方案正在创建问题,并且它可能不会产生问题,那么另一种方法是为要使用标识列和虚拟字段创建的每个id类型创建一个表< / p>

即:

 ABtypeID (ABID int identity(1,1), dummy varchar(1))

然后,您可以在此表中插入记录,并使用内置函数来检索标识。

insert ABTypeID (dummy) values (null)
select Scope_Identity()

您可以根据需要从这些表中删除,并在年底截断它们以重置ID计数器。

您甚至可以将插件包装在回滚的事务中 - 标识值不受回滚的影响