首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle 自動遞增鍵實作完全指南:Sequence + Trigger 傳統架構與 12c Identity 現代化遷移

     編輯:Oracle 資料庫基礎

兩種實作世代對比

特性Sequence + Trigger(11g 及以前)Identity Column(12c+)
語法複雜度建立 Sequence、Trigger 兩個物件單一 GENERATED AS IDENTITY 子句
效能觸發器每列開銷內核層級實作,零開銷
匯入匯出序列值易錯位原生支援正確遷移
指定值插入Trigger 邏輯控制GENERATED BY DEFAULT 選項
相容性所有版本12.1+

傳統架構:Sequence + Trigger 完整實作

1. 建立資料表

CREATE TABLE s_depart (
  depart_id   NUMBER NOT NULL,
  depart_name NVARCHAR2(40) NOT NULL,
  depart_order NUMBER DEFAULT 0,
  CONSTRAINT pk_s_depart PRIMARY KEY (depart_id)
);

2. 建立 Sequence

CREATE SEQUENCE s_s_depart
  MINVALUE 1
  MAXVALUE 999999999999999999999999999
  START WITH 1
  INCREMENT BY 1
  NOCACHE
  NOORDER;  -- RAC 環境建議 ORDER 保證全域有序

參數解析:

  • CACHE n:預載 n 個值至記憶體,提升效能;崩潰會導致跳號。關鍵業務建議 NOCACHE
  • CYCLE:到達最大值後循環,PK 必須 NOCYCLE
  • ORDER:RAC 環境保證跨節點有序,單機可 NOORDER 提升效能

3. 建立 Trigger

CREATE OR REPLACE TRIGGER tri_test_id
BEFORE INSERT ON s_depart
FOR EACH ROW
DECLARE
  v_next_id NUMBER;
BEGIN
  IF :new.depart_id IS NULL OR :new.depart_id = 0 THEN
    SELECT s_s_depart.NEXTVAL INTO v_next_id FROM DUAL;
    :new.depart_id := v_next_id;
  END IF;
END;
/

關鍵點:

  • BEFORE INSERT:在寫入前賦值
  • :new.depart_id:參考新列值
  • 條件判斷允許應用層選擇性指定值(傳入非 NULL/0 時不覆蓋)

4. 測試驗證

INSERT INTO s_depart (depart_name, depart_order) VALUES ('IT', 1);
INSERT INTO s_depart (depart_id, depart_name, depart_order) VALUES (100, 'HR', 2); -- 指定值
INSERT INTO s_depart (depart_name, depart_order) VALUES ('Finance', 3);

SELECT * FROM s_depart ORDER BY depart_id;
-- 結果:1 IT, 3 Finance, 100 HR

現代化架構:12c Identity Column

CREATE TABLE s_depart_modern (
  depart_id   NUMBER GENERATED ALWAYS AS IDENTITY,
  depart_name NVARCHAR2(40) NOT NULL,
  depart_order NUMBER DEFAULT 0,
  CONSTRAINT pk_s_depart_modern PRIMARY KEY (depart_id)
);

等價於:

-- 內部自動建立序列 SYS_ISEQ$_xxxxxx
-- 內部自動建立隱藏觸發器

進階選項

-- 允許指定值(相當於 BY DEFAULT)
depart_id NUMBER GENERATED BY DEFAULT AS IDENTITY

-- 起始值、間距、快取
depart_id NUMBER GENERATED ALWAYS AS IDENTITY
  START WITH 1000 INCREMENT BY 10 CACHE 20

Sequence 進階管理操作

-- 查看序列定義
SELECT sequence_name, min_value, max_value, increment_by, cache_size, last_number
FROM user_sequences WHERE sequence_name = 'S_S_DEPART';

-- 修改序列(不可改 START WITH,需 DROP/CREATE)
ALTER SEQUENCE s_s_depart INCREMENT BY 5 MAXVALUE 10000 CYCLE NOCACHE;

-- 取得當前值/下一值
SELECT s_s_depart.CURRVAL FROM DUAL;  -- 需先在 Session 呼叫過 NEXTVAL
SELECT s_s_depart.NEXTVAL FROM DUAL;

-- 刪除序列
DROP SEQUENCE s_s_depart;

實務常見陷阱與解決

問題原因解決
跳號CACHE 值在 Instance Crash 遺失關鍵表用 NOCACHE;接受跳號為常態
ORA-08002: sequence not yet definedSession 未呼叫 NEXTVAL 就用 CURRVAL先執行 NEXTVAL 或改用 Identity
RAC 環境序列不連續各節點各自 CACHE使用 ORDER 或 NOCACHE
匯入後序列值小於表中最大值IMPDP 不自動對齊序列匯入後手動 ALTER SEQUENCE ... RESTART START WITH (MAX(id)+1)
Trigger 遞迴錯誤Trigger 內再次 INSERT 同表使用 WHEN (NEW.id IS NULL) 條件或複合觸發器

遷移檢核表(Sequence+Trigger → Identity)

  1. 確認目標環境 12.1+
  2. 識別所有使用序列的表與欄位
  3. 測試環境建立 Identity 表,驗證應用程式相容性(特別是指定值插入邏輯)
  4. 匯出資料 → 建立 Identity 結構 → 匯入資料 → 手動對齊序列值
  5. 移除舊 Trigger、Sequence 物件
  6. 更新文件與部署腳本

完整範例腳本(可直接執行)

-- 清理舊物件
DROP TABLE s_depart PURGE;
DROP SEQUENCE s_s_depart;
DROP TRIGGER tri_test_id;

-- 傳統實作
CREATE TABLE s_depart (depart_id NUMBER NOT NULL, depart_name NVARCHAR2(40) NOT NULL, CONSTRAINT pk_s_depart PRIMARY KEY (depart_id));
CREATE SEQUENCE s_s_depart START WITH 1 NOCACHE;
CREATE OR REPLACE TRIGGER tri_test_id BEFORE INSERT ON s_depart FOR EACH ROW BEGIN IF :new.depart_id IS NULL THEN SELECT s_s_depart.NEXTVAL INTO :new.depart_id FROM DUAL; END IF; END;
/

-- 現代實作
CREATE TABLE s_depart_new (depart_id NUMBER GENERATED ALWAYS AS IDENTITY, depart_name NVARCHAR2(40) NOT NULL, CONSTRAINT pk_s_depart_new PRIMARY KEY (depart_id));

-- 測試
INSERT INTO s_depart (depart_name) VALUES ('Traditional');
INSERT INTO s_depart_new (depart_name) VALUES ('Modern');
SELECT * FROM s_depart;
SELECT * FROM s_depart_new;
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved