Mat*_*ima 6 database-design sql-server delete sql-server-2014
我有这张桌子,打算有很多活动。其中的任何内容都表明用户操作仍在等待中。一旦删除,它将表明该操作不再处于待处理状态。系统的其他区域依赖于此,因此表格本身并不能真正解释这种情况。但是,我的问题是我是否应该保持表原样并删除,当挂起的操作完成时,或者我是否应该添加一个标志列并更新。
请注意,记录可能会在插入的同一秒内被删除。我希望每秒最多支持 100 个,但不希望将其作为限制。
我使用的是 SQL Server 2014 企业版。
这是表的定义(所有索引都基于使用此表的选择查询):
CREATE TABLE [dbo].[OpenRounds](
[OpenRoundId] [bigint] IDENTITY(1,1) NOT NULL,
[UserId] [int] NOT NULL,
[GameActivityId] [bigint] NOT NULL,
[VendorId] [int] NOT NULL,
[Date] [datetime] NOT NULL,
[UserBonusId] [bigint] NULL,
[VendorRoundId] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_GamesOpenRounds] PRIMARY KEY CLUSTERED
(
[OpenRoundId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_GameOpenRoundsUserIdUserBonusId] ON [dbo].[OpenRounds]
(
[UserId] ASC,
[UserBonusId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
CREATE NONCLUSTERED INDEX [IX_GameOpenRoundsUserIdVendorIdVendorRoundId] ON [dbo].[OpenRounds]
(
[UserId] ASC,
[VendorId] ASC,
[VendorRoundId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
CREATE NONCLUSTERED INDEX [IX_GameOpenRoundsVendorIdVendorRoundId] ON [dbo].[OpenRounds]
(
[VendorId] ASC,
[VendorRoundId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
Run Code Online (Sandbox Code Playgroud)
如果您设计系统的目的是支持每秒数千个事务,您可能希望设计一个不依赖于插入的排队系统。插入的成本很高,并且取决于队列表的设计,可能会导致队列表的最后一页成为限制系统吞吐量速率的“热点”。
以下设计允许通过 Rounds 表进行多达 100,000 个并发事务。
CREATE TABLE dbo.OpenRounds
(
OpenRoundID BIGINT NOT NULL
CONSTRAINT PK_GamesOpenRounds
PRIMARY KEY CLUSTERED
, UserID INT NULL
, GameActivityID BIGINT NULL
, VendorID INT NULL
, RoundDate DATETIME NULL
, UserBonusID BIGINT NULL
, VendorRoundID NVARCHAR(50) NULL
, ReferenceCount INT NOT NULL
CONSTRAINT DF_OpenRounds_ReferenceCount
DEFAULT ((0))
);
INSERT INTO dbo.OpenRounds (OpenRoundID)
SELECT TOP(100000) /* top 100,000 -> we're creating 100,000 slots */
rn = ROW_NUMBER() OVER (ORDER BY o1.object_id)
FROM sys.objects o1
, sys.objects o2
, sys.objects o3;
GO
CREATE SEQUENCE dbo.RoundSlotSequence
AS INT
START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 100000
CYCLE
CACHE 10000;
GO
Run Code Online (Sandbox Code Playgroud)
上面创建的序列设计为在达到 100,000 后滚动。这与我们在dbo.OpenRounds表中创建的行数一致。
要将消息推送到 OpenRounds 表中,您可以使用以下过程:
CREATE PROCEDURE dbo.PushRound
(
@UserID INT
, @GameActivityID BIGINT
, @VendorID INT
, @RoundDate DATETIME
, @UserBonusID BIGINT
, @VendorRoundID NVARCHAR(50)
)
AS
BEGIN
DECLARE @SlotID INT;
DECLARE @SequenceID INT;
DECLARE @TryCount INT = 0;
SELECT @SequenceID = NEXT VALUE FOR dbo.RoundSlotSequence;
WHILE @SlotID IS NULL AND @TryCount < 50
BEGIN
UPDATE dbo.OpenRounds WITH (ROWLOCK)
SET ReferenceCount = ReferenceCount + 1
, @SlotID = OpenRoundID
, UserID = @UserID
, GameActivityID = @GameActivityID
, VendorID = @VendorID
, RoundDate = @RoundDate
, UserBonusID = @UserBonusID
, VendorRoundID = @VendorRoundID
WHERE ReferenceCount = 0
AND OpenRoundID = @SequenceID;
/* If @SlotID IS NULL the slot was not available
- wait 5 milliseconds before checking again
to see if the slot is open
*/
IF @SlotID IS NULL WAITFOR DELAY '00:00:00.005';
SET @TryCount += 1;
END
IF @SlotID IS NULL
RETURN 1
ELSE
RETURN @SlotID
END;
GO
Run Code Online (Sandbox Code Playgroud)
此过程可用于从 OpenRounds 表中获取下一条消息。通常,这将在一个循环内运行,该循环不断寻找要处理的行:
CREATE PROCEDURE dbo.PopRound
(
@UserID INT OUTPUT
, @GameActivityID BIGINT OUTPUT
, @VendorID INT OUTPUT
, @RoundDate DATETIME OUTPUT
, @UserBonusID BIGINT OUTPUT
, @VendorRoundID NVARCHAR(50) OUTPUT
, @MaxRetries INT = 2000 /* 10 seconds
default maximum wait time */
)
AS
BEGIN
DECLARE @SlotID INT;
DECLARE @TryCount INT = 0;
WHILE @SlotID IS NULL AND @TryCount < @MaxRetries
BEGIN
UPDATE dbo.OpenRounds WITH (ROWLOCK)
SET ReferenceCount = ReferenceCount - 1
, @SlotID = OpenRoundID
, @UserID = UserID
, @GameActivityID = GameActivityID
, @VendorID = VendorID
, @RoundDate = RoundDate
, @UserBonusID = UserBonusID
, @VendorRoundID = VendorRoundID
WHERE ReferenceCount > 0;
IF @SlotID IS NULL WAITFOR DELAY '00:00:00.005';
SET @TryCount += 1;
END
END;
GO
Run Code Online (Sandbox Code Playgroud)
这种设计大致基于我在Exadat.co.uk超级扩展 SQL Server 站点上看到的概念,作者是 Chris Adkin。他的站点提供了关于将 SQL Server 推向极限的出色材料和指导,包括有关硬件以及 SQL Server 如何与其交互的非常深入的详细信息。我与 Chris 或他的网站没有任何关联。
| 归档时间: |
|
| 查看次数: |
3386 次 |
| 最近记录: |