sql-server - SQL Server 依赖标识 - 有这样的事情吗?

标签 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

(谁能告诉我如何在此处格式化示例表的 secret ?)

我希望能够像这样声明一个从属身份列:
ItemID [int] Identity(RoomID,1,1) NOT NULL[Rooms]中的新行应该触发 ItemID 的最大值的测试哪里RoomID = @roomID并添加 1。

而不是更新 RoomID使用删除并插入所需的数据。

现在我以编程方式这样做:
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

那么,有这样的功能吗?

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

最佳答案

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

将您的表更改为具有主键,并允许 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 所建议的,我使用了 10 个线程的 SQL Query Stress 来查看此触发器在负载下会发生什么。我根本没有得到任何重复(使用默认隔离级别),但我确实遇到了我预期的死锁负载。

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

使用触发器方法,我会遇到如下死锁和结果:
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 行。
  • 使用默认隔离级别的触发器版本成功 没有任何死锁或错误 并且运行速度非常快。

  • 使用带有隔离级别 = 可序列化的触发器会导致死锁,因此只有 40% 的插入成功(但不会因重复而出现异常)。

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

    关于sql-server - SQL Server 依赖标识 - 有这样的事情吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10769780/

    相关文章:

    sql-server - 基于两列对行进行分组并包括聚合列

    sql - 如何包含行号但显示平局?

    sql-server - 为指标 SSRS BIDS 添加多个规则

    sql-在执行中超出变量大小?

    sql-server - 在 Reporting Services 报表中隐藏页面滚动控件

    c# - c#中的连接字符串

    sql - SQL 2008 r2 有刷新存储过程的热键吗?

    sql - 性能瓶颈 - Linq to SQL 或数据库 - 我怎么知道?

    sql - 内连接转换失败

    sql-server - Entity Framework 中的新对象 - 主键问题