SQL Server依赖的身份 - 有这样的事情吗?

时间:2012-05-26 21:07:15

标签: sql-server sql-server-2008

我使用的是SQL Server 2008 R2。

我正在寻找一种我描述为依赖身份的功能。

我将以一个例子来解释。

考虑这样一个表:

脚本

CREATE TABLE [dbo].[Rooms](
    [RoomID] [int] NOT NULL,
    [ItemID] [int] NOT NULL,
    [ItemDescription] [nvarchar] (250))
GO

数据:

RoomID  ItemID  ItemDescription
------  ------  --------------- 
7       1       Door
7       2       Window (West)
7       3       Window (North)
8       1       Door
8       2       Table #1
8       3       Table #2
7       4       Table #1 
8       4       Chair #1 
7       5       Table #2 
7       6       Table #3 
8       5       Chair #2

(有人能告诉秘密如何格式化示例表吗?)

我希望能够像这样声明一个依赖的标识列:

ItemID [int] Identity(RoomID,1,1) NOT NULL

[Rooms]中的新行应触发对ItemID RoomID的最大值的测试,其中@roomID = RoomID并添加1。

使用删除并插入所需数据,而不是使用DECLARE @roomID INT SET @roomID = 7 INSERT INTO [Allocation].[dbo].[Rooms] ([RoomID], [ItemID], [ItemDescription]) VALUES (@roomID, (SELECT max([ItemID])+1 FROM [Allocation].[dbo].[Rooms] WHERE [RoomID]=@roomID) ,'Chair #1') GO 中的更改进行更新。

现在我以编程方式执行此操作:

{{1}}

那么,有这样的功能吗?

在可能的情况下没有,在给定特定的表,父列和从属标识列的情况下,我可以自动编程服务器为我设置下一个从属身份吗?

1 个答案:

答案 0 :(得分:1)

您可以使用触发器和索引来提高性能并确保没有重复项。

将表更改为具有主键,并为ItemID

允许null
CREATE TABLE [dbo].[Rooms](
    [RoomID] [int] NOT NULL,
    [ItemID] [int] NULL,
    [ItemDescription] [nvarchar](250) NULL,
    [Id] [int] IDENTITY(1,1) NOT NULL,
    CONSTRAINT [PK_Rooms] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )
)

然后添加触发器

CREATE TRIGGER RoomTrigger
   ON  Rooms
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;

    update Rooms
    set 
        ItemID = (select coalesce(MAX(itemid), 0) + 1 
                      from Rooms r where r.RoomID = inserted.RoomID )
    from
        inserted where Rooms.Id = inserted.Id

END

然后你可以这样做

insert into Rooms (RoomID, ItemDescription) values (1, 'Test')
insert into Rooms (RoomID, ItemDescription) values (1, 'Test')

导致

RoomID  ItemID ItemDescription Id
2       0      Test            1
2       1      Test            2

正如marc_s所建议的那样,我使用SQL Query Stress和10个线程来查看加载时此触发器会发生什么。我没有得到任何重复项(使用默认的隔离级别),但我确实得到了大量的死锁,正如我所期望的那样。

使用问题中的原始查询,我得到了很多重复。

使用触发器方法我会遇到死锁和结果:

RoomID ItemID ItemDescription Id
1      6      Test            6
1      7      Test            9
1      8      Test            902
1      9      Test            903

此处ItemID是连续的,但是1000行中约有900行未能插入,在Id中留下较大的间隙。

如果我们添加以下索引:

CREATE UNIQUE NONCLUSTERED INDEX [IX_Rooms] ON [dbo].[Rooms] 
(
    [RoomID] ASC,
    [ItemID] ASC
)

为了保证没有重复,并提高计算特定RoomID的Max(ItemId)的性能,那么现在:

  • 来自问题的原始查询会导致重复,并且只能设置插入500行。
  • 使用默认隔离级别的触发器版本成功没有任何死锁或错误并且运行速度非常快。

使用具有隔离级别= serializable的触发器会导致死锁,因此只有40%的插入成功(但由于重复而没有例外)。

作为最终测试尝试使用触发器+50个线程+隔离级别=默认值。 没有错误