DB2 Sequence(序列)是獨立於資料表的編號產生器,提供高效能、無鎖競爭的主鍵值生成機制,是替代 MAX(id)+1 模式的最佳選擇。本文涵蓋建立語法、調用方式、快取機制與實戰優化。
CREATE SEQUENCE schema.seq_name
AS BIGINT -- 資料類型:SMALLINT/INTEGER/BIGINT/DECIMAL
START WITH 1 -- 起始值
INCREMENT BY 1 -- 遞增值(負值為遞減)
NO MAXVALUE -- 無上限(或指定 MAXVALUE 9999999999)
NO MINVALUE -- 無下限
CYCLE -- 達上限後循環(預設 NO CYCLE 報錯)
CACHE 20 -- 記憶體預先配置 20 個值(效能關鍵,預設 20)
NO ORDER; -- 不保證跨分區全域有序(效能最佳)
| 參數 | 建議值 | 說明 |
|---|---|---|
| CACHE | 20 ~ 1000 | 值越大越少同步 I/O,但資料庫異常關閉會遺失未使用的快取值(造成間隙) |
| CYCLE | 視業務 | 主鍵通常 NO CYCLE;循環編號可用 CYCLE |
| ORDER | NO ORDER | 分區環境下 NO ORDER 效能大幅優於 ORDER |
| 資料類型 | BIGINT | 64 位元整數支援 9.2 兆次遞增,足應對極高併發 |
-- 取得下一個值(最常用)
VALUES NEXT VALUE FOR schema.seq_name;
-- 或
SELECT NEXT VALUE FOR schema.seq_name FROM SYSIBM.SYSDUMMY1;
-- 取得當前會話最近使用的值
VALUES PREVIOUS VALUE FOR schema.seq_name;
-- 在 INSERT 中直接使用
INSERT INTO audit_log (log_id, msg)
VALUES (NEXT VALUE FOR audit_seq, 'User login');
-- 批次插入自動生成連續主鍵
INSERT INTO audit_log (log_id, msg)
SELECT NEXT VALUE FOR audit_seq, 'Batch ' || CAST(ROW_NUMBER() OVER() AS VARCHAR(10))
FROM SYSCAT.TABLES FETCH FIRST 1000 ROWS ONLY;
CREATE SEQUENCE global_id_seq AS BIGINT START WITH 1 CACHE 100;
INSERT INTO orders (order_id, ...) VALUES (NEXT VALUE FOR global_id_seq, ...);
INSERT INTO shipments (ship_id, ...) VALUES (NEXT VALUE FOR global_id_seq, ...);
INSERT INTO invoices (inv_id, ...) VALUES (NEXT VALUE FOR global_id_seq, ...);
優點:跨表主鍵全域唯一,簡化合併查詢與資料整合。缺點:單點熱點,極高併發考慮分區 Sequence。
| 特性 | IDENTITY COLUMN | SEQUENCE |
|---|---|---|
| 綁定對象 | 單一資料表欄位 | 獨立物件,多表共用 |
| ALTER 靈活性 | 受限(需重建表) | 隨時 ALTER SEQUENCE |
| 跨分區有序 | ORDER 選項支援 | ORDER/NO ORDER 可選 |
| 效能 | 表級鎖競爭 | 獨立快取,無表鎖 |
| 遷移相容性 | 標準 SQL | DB2/Oracle/PostgreSQL 相容 |
建議:新系統優先使用 Sequence;既有 Identity Column 系統維持現狀。
-- 僅在成功插入時消耗序列值(需配合應用邏輯)
BEGIN ATOMIC
DECLARE v_id BIGINT;
SET v_id = NEXT VALUE FOR order_seq;
INSERT INTO orders (order_id, ...) VALUES (v_id, ...);
-- 失敗時序列值已消耗,間隙不可避免
END;
注意:Sequence 設計上不保證無間隙(快取遺失、Rollback、Crash 皆造成間隙),業務若要求連續編號需另行設計。
-- 查看序列定義
db2 "select * from syscat.sequences where seqschema='SCHEMA' and seqname='SEQ_NAME'"
-- 查看當前快取狀態(需 SYSADM)
db2 "select * from table(sysproc.snap_get_seq('SCHEMA', 'SEQ_NAME')) as t"
-- 修改快取大小
db2 "alter sequence schema.seq_name cache 100"
-- 重設序列(謹慎使用)
db2 "alter sequence schema.seq_name restart with 10000"
-- 刪除序列
db2 "drop sequence schema.seq_name"
SELECT NEXT VALUE ... FROM SYSIBM.SYSDUMMY1 可能成為瓶頸,改用 VALUES NEXT VALUE ...SELECT MAX(id) - COUNT(*) FROM table 估算間隙率| 錯誤 | 原因 | 解決 |
|---|---|---|
| SQL0348N | 序列達 MAXVALUE 且 NO CYCLE | ALTER SEQUENCE 設定 CYCLE 或擴大 MAXVALUE |
| SQL0802N | 數值溢位(超出資料類型範圍) | 改用 BIGINT 或 DECIMAL(31,0) |
| SQL0723N | 觸發程序中使用 NEXT VALUE 違反限制 | 移至應用層或 BEFORE INSERT 觸發程序外部調用 |