為什麼需要自訂 Sequence?
IDENTITY 只能產生單純遞增數字,無法組合成 YYYYMMDD00001 等業務格式。
MAX(id)+1 在高併發下極易產生重複鍵值。
- 集中式序號表(名稱、起始值、遞增值、目前值)在高併發時鎖定爭用嚴重。
高併發安全方案:利用 IDENTITY + 刪除舊列
-- 為每個業務序號建立專屬表
CREATE TABLE SeqT_0101001 (
SeqID INT IDENTITY(1,1) PRIMARY KEY, -- 利用身分欄位保證唯一遞增
SeqVal VARCHAR(1) -- 虛擬欄位,僅佔位
);
-- 取得新序號的預存程序
CREATE PROCEDURE P_GetNewSeqVal_SeqT_0101001
AS
BEGIN
SET NOCOUNT ON;
DECLARE @NewSeqValue INT;
-- 插入一列觸發 IDENTITY 產生新值
INSERT INTO SeqT_0101001 (SeqVal) VALUES ('a');
-- 取得剛插入的身分值
SET @NewSeqValue = SCOPE_IDENTITY();
-- 刪除已用過的列(READPAST 跳過被鎖列,避免阻塞)
DELETE FROM SeqT_0101001 WITH (READPAST);
RETURN @NewSeqValue;
END
呼叫方式與格式化
DECLARE @NewSeqVal INT;
EXEC @NewSeqVal = P_GetNewSeqVal_SeqT_0101001;
PRINT @NewSeqVal;
-- 組合成 20080724000056 格式
SELECT CONVERT(CHAR(8), GETDATE(), 112) + RIGHT('00000' + CAST(@NewSeqVal AS VARCHAR(5)), 5) AS mySeq;
核心優勢分析
| 特性 | 傳統序號表 | 本方案 |
| 併發效能 | 單列更新鎖定,嚴重阻塞 | INSERT + DELETE,鎖定粒度極小,吞吐量達千次/秒 |
| 間隙處理 | 無間隙(若交易回滾會留間隙) | IDENTITY 本身允許間隙,符合 Sequence 語意 |
| 擴充性 | 單表熱點 | 每個序號獨立表,零干擾 |
限制與替代方案
- 無法直接在
SELECT 中呼叫(需透過預存程序或函數包裝)。
- SQL Server 2012+ 內建
CREATE SEQUENCE,支援 NEXT VALUE FOR 直接在查詢中使用,建議優先使用原生功能。
- 若版本較舊且併發極高,本方案為可行替代;併發中低可考慮
sp_getapplock 序列化傳統寫法。