আমার কাছে একটি টেবিল রয়েছে যা উত্তরাধিকারের অ্যাপ্লিকেশন দ্বারা IDENTITY
অন্যান্য বিভিন্ন সারণীতে ক্ষেত্রের বিকল্প হিসাবে ব্যবহৃত হয় ।
টেবিলের প্রতিটি সারি LastID
ক্ষেত্রের জন্য ব্যবহৃত সর্বশেষ ব্যবহৃত আইডি সঞ্চয় করে IDName
।
মাঝেমধ্যে সঞ্চিত সংগ্রহটি একটি অচলাবস্থা পায় - আমি বিশ্বাস করি যে আমি একটি উপযুক্ত ত্রুটি হ্যান্ডলার তৈরি করেছি; তবে আমি আগ্রহী যে এই পদ্ধতিটি আমার যেমন মনে হয় ঠিক তেমন কাজ করে কিনা, বা আমি যদি এখানে ভুল গাছটি ছাঁটাই করছি।
আমি মোটামুটি নিশ্চিত যে কোনও টেড লক ছাড়াই এই টেবিলটি অ্যাক্সেস করার কোনও উপায় থাকতে হবে।
ডাটাবেস নিজেই সাথে কনফিগার করা হয় READ_COMMITTED_SNAPSHOT = 1
।
প্রথমত, এখানে টেবিলটি রয়েছে:
CREATE TABLE [dbo].[tblIDs](
[IDListID] [int] NOT NULL
CONSTRAINT PK_tblIDs
PRIMARY KEY CLUSTERED
IDENTITY(1,1) ,
[IDName] [nvarchar](255) NULL,
[LastID] [int] NULL,
);
এবং IDName
মাঠে অবিচ্ছিন্ন সূচক :
CREATE NONCLUSTERED INDEX [IX_tblIDs_IDName]
ON [dbo].[tblIDs]
(
[IDName] 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
, FILLFACTOR = 80
);
GO
কিছু নমুনা তথ্য:
INSERT INTO tblIDs (IDName, LastID)
VALUES ('SomeTestID', 1);
INSERT INTO tblIDs (IDName, LastID)
VALUES ('SomeOtherTestID', 1);
GO
সারণীতে সঞ্চিত মানগুলি আপডেট করার জন্য ব্যবহৃত সঞ্চিত পদ্ধতিটি এবং পরবর্তী আইডিটি ফেরত দিন:
CREATE PROCEDURE [dbo].[GetNextID](
@IDName nvarchar(255)
)
AS
BEGIN
/*
Description: Increments and returns the LastID value from tblIDs
for a given IDName
Author: Max Vernon
Date: 2012-07-19
*/
DECLARE @Retry int;
DECLARE @EN int, @ES int, @ET int;
SET @Retry = 5;
DECLARE @NewID int;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET NOCOUNT ON;
WHILE @Retry > 0
BEGIN
BEGIN TRY
BEGIN TRANSACTION;
SET @NewID = COALESCE((SELECT LastID
FROM tblIDs
WHERE IDName = @IDName),0)+1;
IF (SELECT COUNT(IDName)
FROM tblIDs
WHERE IDName = @IDName) = 0
INSERT INTO tblIDs (IDName, LastID)
VALUES (@IDName, @NewID)
ELSE
UPDATE tblIDs
SET LastID = @NewID
WHERE IDName = @IDName;
COMMIT TRANSACTION;
SET @Retry = -2; /* no need to retry since the operation completed */
END TRY
BEGIN CATCH
IF (ERROR_NUMBER() = 1205) /* DEADLOCK */
SET @Retry = @Retry - 1;
ELSE
BEGIN
SET @Retry = -1;
SET @EN = ERROR_NUMBER();
SET @ES = ERROR_SEVERITY();
SET @ET = ERROR_STATE()
RAISERROR (@EN,@ES,@ET);
END
ROLLBACK TRANSACTION;
END CATCH
END
IF @Retry = 0 /* must have deadlock'd 5 times. */
BEGIN
SET @EN = 1205;
SET @ES = 13;
SET @ET = 1
RAISERROR (@EN,@ES,@ET);
END
ELSE
SELECT @NewID AS NewID;
END
GO
সঞ্চিত প্রকল্পের নমুনা সম্পাদন:
EXEC GetNextID 'SomeTestID';
NewID
2
EXEC GetNextID 'SomeTestID';
NewID
3
EXEC GetNextID 'SomeOtherTestID';
NewID
2
সম্পাদনা করুন:
আমি একটি নতুন সূচক যুক্ত করেছি, যেহেতু বিদ্যমান সূচক IX_tblIDs_Name এসপি ব্যবহার করছে না; আমি ধরে নিই যে ক্যোরি প্রসেসর ক্লাস্টারড ইনডেক্স ব্যবহার করছে কারণ এটি লাস্টআইডি-তে সঞ্চিত মান প্রয়োজন। যাইহোক, এই সূচকটি প্রকৃত বাস্তবায়ন পরিকল্পনার দ্বারা ব্যবহৃত হয়:
CREATE NONCLUSTERED INDEX IX_tblIDs_IDName_LastID
ON dbo.tblIDs
(
IDName ASC
)
INCLUDE
(
LastID
)
WITH (FILLFACTOR = 100
, ONLINE=ON
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON);
সম্পাদনা # 2:
@ অ্যারোনবার্ট্র্যান্ড যে পরামর্শ দিয়েছিল এবং তাতে কিছুটা সংশোধন করেছে আমি তা গ্রহণ করেছি। এখানে সাধারণ ধারণাটি অপ্রয়োজনীয় লকিং অপসারণের জন্য এবং সামগ্রিকভাবে এসপিকে আরও দক্ষ করে তোলার জন্য বিবৃতিটি পরিমার্জন করা।
কোড নিচে থেকে উপরের কোড প্রতিস্থাপন BEGIN TRANSACTION
করতে END TRANSACTION
:
BEGIN TRANSACTION;
SET @NewID = COALESCE((SELECT LastID
FROM dbo.tblIDs
WHERE IDName = @IDName), 0) + 1;
IF @NewID = 1
INSERT INTO tblIDs (IDName, LastID)
VALUES (@IDName, @NewID);
ELSE
UPDATE dbo.tblIDs
SET LastID = @NewID
WHERE IDName = @IDName;
COMMIT TRANSACTION;
যেহেতু আমাদের কোডটি 0 টি দিয়ে এই টেবিলটিতে কখনই কোনও রেকর্ড যুক্ত করে না LastID
আমরা এই ধারণাটি তৈরি করতে পারি যে @ নিউইডআইডি যদি 1 হয় তবে সেই উদ্দেশ্যটি তালিকায় একটি নতুন আইডি যুক্ত করা হয়, অন্যথায় আমরা তালিকার একটি বিদ্যমান সারি আপডেট করছি।
SERIALIZABLE
এখানে চলেছেন ।