4

SQL Server 2008 R2 を使用しています。

依存 ID として説明する機能を探しています。

例で説明します。

次のようなテーブルを考えてみましょう:

脚本

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

(ここでサンプルテーブルをフォーマットする方法の秘密を誰か教えてもらえますか?)

次のように、依存する ID 列を宣言できるようになりたいと思います。

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

の新しい行は、 where =[Rooms]の最大値のテストをトリガーし、1 を追加する必要があります。ItemIDRoomID@roomID

使用の変更で更新する代わりに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

それで、そのような機能はありますか?

おそらく何もない場合、特定のテーブル、親列、および依存 ID 列を指定して、次の依存 ID を自動的に設定するようにサーバーをプログラムできますか?

4

1 に答える 1

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が示唆しているように、負荷がかかった状態でこのトリガーがどうなるかを確認するために、10スレッドのSQLクエリストレスを使用しました。(デフォルトの分離レベルを使用して)重複はまったくありませんでしたが、予想どおりに大量のデッドロックが発生しました。

質問の元のクエリを使用すると、多くの重複が発生します。

トリガーアプローチを使用すると、デッドロックが発生し、次のような結果になります。

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スレッド+分離レベル=デフォルトで試行しました。 エラーなし

于 2012-05-26T21:22:40.400 に答える