为所有表生成顺序 guid 的存储过程

Stored procedure to generate sequential guid for all tables

这很可能是重复的,但我似乎找不到与我的用例足够接近的东西。

由于视图而不是触发器等各种原因,我无法将 OUTPUT 子句与 INSERT 语句一起使用来检索系统生成的 GUID NEWSEQUENTIALID().

我的一个想法是使用存储过程生成 GUID

SET NOCOUNT ON;
GO

IF ( OBJECT_ID( N'[dbo].[GETNEXTGUID]' ) IS NOT Null )
    DROP PROCEDURE [dbo].[GETNEXTGUID];
GO

CREATE PROCEDURE [dbo].[GETNEXTGUID]
    (@NextId UNIQUEIDENTIFIER OUTPUT)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Sequence TABLE([KEY] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(), [DUMMY] BIT);

    INSERT INTO @Sequence ([DUMMY]) VALUES (0);

    SELECT @NextId = [KEY] FROM @Sequence;
END
GO

DECLARE @NextId UNIQUEIDENTIFIER;

EXECUTE [dbo].[GETNEXTGUID] @NextId OUTPUT;

PRINT @NextId;

然后可以将生成的 GUID 插入到 table 中,并且还可以缓解 @@IDENTITYIDENT_CURRENT 列困扰 IDENTITY 的问题,等等

即使在测试之后我也没有足够的知识来权威地说这是一个真正可行的解决方案还是只是应用 "somewhat" 清洁器 NEWID() 的冗长方法,因为以下事实它使用的是临时 table,每次调用后都会被销毁。

我尝试使用两个临时 tables,它们的序号似乎是固定的,运行 连续的程序似乎也是固定的。

SET NOCOUNT ON;
GO

IF (OBJECT_ID( N'[dbo].[GETNEXTGUID]') IS NOT Null)
    DROP PROCEDURE [dbo].[GETNEXTGUID];
GO

CREATE PROCEDURE [dbo].[GETNEXTGUID]
    (@NextId1 UNIQUEIDENTIFIER OUTPUT,
     @NextId2 UNIQUEIDENTIFIER OUTPUT)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Sequence1 TABLE ([KEY] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(), [DUMMY] BIT);
    DECLARE @Sequence2 TABLE ([KEY] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(), [DUMMY] BIT);

    INSERT INTO @Sequence1 ([DUMMY]) VALUES (0);
    INSERT INTO @Sequence2 ([DUMMY]) VALUES (0);

    SELECT @NextId1 = [KEY] FROM @Sequence1;
    SELECT @NextId2 = [KEY] FROM @Sequence2;
END
GO

DECLARE @NextId1 UNIQUEIDENTIFIER;
DECLARE @NextId2 UNIQUEIDENTIFIER;

EXECUTE [dbo].[GETNEXTGUID] @NextId1 OUTPUT, @NextId2 OUTPUT;
PRINT @NextId1; PRINT @NextId2;

EXECUTE [dbo].[GETNEXTGUID] @NextId1 OUTPUT, @NextId2 OUTPUT;
PRINT @NextId1; PRINT @NextId2;

EXECUTE [dbo].[GETNEXTGUID] @NextId1 OUTPUT, @NextId2 OUTPUT;
PRINT @NextId1; PRINT @NextId2;

EXECUTE [dbo].[GETNEXTGUID] @NextId1 OUTPUT, @NextId2 OUTPUT;
PRINT @NextId1; PRINT @NextId2;

EXECUTE [dbo].[GETNEXTGUID] @NextId1 OUTPUT, @NextId2 OUTPUT;
PRINT @NextId1; PRINT @NextId2;

结果:

AAAFD869-E814-EA11-A2FA-00155D0A020C
ABAFD869-E814-EA11-A2FA-00155D0A020C
ACAFD869-E814-EA11-A2FA-00155D0A020C
ADAFD869-E814-EA11-A2FA-00155D0A020C
AEAFD869-E814-EA11-A2FA-00155D0A020C
AFAFD869-E814-EA11-A2FA-00155D0A020C
B0AFD869-E814-EA11-A2FA-00155D0A020C
B1AFD869-E814-EA11-A2FA-00155D0A020C
B2AFD869-E814-EA11-A2FA-00155D0A020C
B3AFD869-E814-EA11-A2FA-00155D0A020C

如果有经验丰富的人提供他们的见解,我将不胜感激。

我不知道,你真正需要什么,但你可以试试这个:

CREATE SEQUENCE dbo.testSeq_13Byte AS DECIMAL(28); /*read about START WITH to enforce a range*/
GO
SELECT NEXT VALUE FOR dbo.testSeq_13Byte;
GO
SELECT CAST(CAST(NEXT VALUE FOR dbo.testSeq_13Byte AS VARBINARY(16)) AS UNIQUEIDENTIFIER);

根据文档,DECIMAL(28) 占用 13 个字节,DECIMAL(38) 占用 17 个字节,GUID 使用 16 个字节。

DECIMAL(28) 的数值范围很大...您可以将其转换为 VARBINARY(16),将其转换为 UNIQUEIDENTIFIER。这应该 return 具有系统范围逻辑的 新 ID

如果你需要这个,你甚至可以将它转换回 DECIMAL(28)

但我们应该记住,依赖数据类型的内部二进制表示总是有点危险。这可能会因版本而异...

所以我创建了以下存储过程来进行测试。它创建了 2 个临时表,这些表将显示生成的 ID 实际上是否是连续的。

SET NOCOUNT ON;
GO

IF (OBJECT_ID( N'[dbo].[GETNEXTGUID]') IS NOT Null)
    DROP PROCEDURE [dbo].[GETNEXTGUID];
GO

CREATE PROCEDURE [dbo].[GETNEXTGUID]
(
    @NextId1 UNIQUEIDENTIFIER OUTPUT,
    @NextId2 UNIQUEIDENTIFIER OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Sequence1 TABLE ([KEY] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(), [DUMMY] BIT);
    DECLARE @Sequence2 TABLE ([KEY] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(), [DUMMY] BIT);

    INSERT INTO @Sequence1 ([DUMMY]) VALUES (0);
    INSERT INTO @Sequence2 ([DUMMY]) VALUES (0);

    SELECT @NextId1 = [KEY] FROM @Sequence1;
    SELECT @NextId2 = [KEY] FROM @Sequence2;
END
GO

然后我 运行 同时跨多个连接进行以下测试。因此测试将调用它自己的两个持久表以及存储过程中的两个临时表。

SET NOCOUNT ON;
GO

DECLARE @Sequence1 TABLE ([KEY] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(), [DUMMY] BIT);
DECLARE @Sequence2 TABLE ([KEY] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(), [DUMMY] BIT);
DECLARE @Count int = 0;
DECLARE @NextId1 UNIQUEIDENTIFIER;
DECLARE @NextId2 UNIQUEIDENTIFIER;

WHILE ( @Count < 100000 )
BEGIN
    EXECUTE [dbo].[GETNEXTGUID] @NextId1 OUTPUT, @NextId2 OUTPUT;
    PRINT @NextId1; PRINT @NextId2;

    INSERT INTO @Sequence1 ([DUMMY]) VALUES (0);
    INSERT INTO @Sequence2 ([DUMMY]) VALUES (0);

    SELECT @NextId1 = [KEY] FROM @Sequence1;
    SELECT @NextId2 = [KEY] FROM @Sequence2;

    PRINT @NextId1; PRINT @NextId2;

    SET @Count += 1;
END
GO

从各种连接中获取结果并对它们进行排序表明,序列在所有 4 个表中都是连续的,无论它们是持久化还是在每次调用时重新创建,因此完全符合要求。

感谢大家的投稿!