約束與分區表看似獨立,實則緊密相關:分區表上的主鍵/唯一約束決定索引類型(LOCAL/GLOBAL),約束狀態控制資料載入效能,分區維護操作需考慮約束驗證成本。本文系統整理五大約束類型、四種狀態語義、修正違規資料流程,並詳細涵蓋五種分區策略、組合分區、維護操作與資料字典。
| 約束 | 語義 | 索引關聯 | 典型場景 |
|---|---|---|---|
| NOT NULL | 欄位不可為空 | 無 | 業務必填欄位 |
| UNIQUE | 值唯一(允許多 NULL) | 自動建立唯一索引 | Email、身分證、UK |
| PRIMARY KEY | NOT NULL + UNIQUE,表僅一個 | 自動建立唯一索引(預設同名) | 實體識別鍵 |
| FOREIGN KEY | 參考父表 PK/UK,維護參考完整性 | 子表 FK 欄位**強烈建議建索引** | 訂單-客戶、明細-主單 |
| CHECK | 自定義條件(不含子查詢、SYSDATE、序列) | 無 | 薪資範圍、狀態碼枚舉 |
| 狀態 | 語法 | 現有資料 | 新資料 | 索引 | 用途 |
|---|---|---|---|---|---|
| ENABLE VALIDATE | DEFAULT | 必須滿足 | 必須滿足 | 存在 | 生產標準 |
| ENABLE NOVALIDATE | ENABLE NOVALIDATE CONSTRAINT | **不檢查** | 必須滿足 | 存在 | 大量載入後快速啟用、異構遷移 |
| DISABLE VALIDATE | DISABLE VALIDATE CONSTRAINT | 必須滿足 | **禁止 DML** | **刪除** | 分區交換、唯讀歸檔 |
| DISABLE NOVALIDATE | DISABLE NOVALIDATE CONSTRAINT | 不檢查 | 不檢查 | **刪除** | 暫停約束、大量載入前 |
-- 建表時定義
CREATE TABLE t (
id NUMBER CONSTRAINT pk_id PRIMARY KEY,
val NUMBER NOT NULL,
code VARCHAR2(10) CONSTRAINT uk_code UNIQUE,
status VARCHAR2(1) CONSTRAINT chk_status CHECK (status IN ('A','I','P')),
parent_id NUMBER CONSTRAINT fk_parent REFERENCES parent_t(id)
);
-- 事後新增/修改/刪除
ALTER TABLE t ADD CONSTRAINT uk_email UNIQUE (email);
ALTER TABLE t MODIFY (val NOT NULL);
ALTER TABLE t DROP CONSTRAINT uk_code;
ALTER TABLE t DROP PRIMARY KEY;
-- 狀態切換
ALTER TABLE t DISABLE NOVALIDATE CONSTRAINT pk_id; -- 載入前
-- 大量載入...
ALTER TABLE t ENABLE NOVALIDATE CONSTRAINT pk_id; -- 載入後快速啟用(不驗證舊資料)
-- 後續需完全驗證時
ALTER TABLE t ENABLE VALIDATE CONSTRAINT pk_id; -- 會檢查所有資料,若違規報錯
場景:欲啟用 PK 約束,但現有資料有重複/NULL。
ALTER TABLE t DROP CONSTRAINT pk_id;@$ORACLE_HOME/rdbms/admin/utlexcpt.sql(建立 EXCEPTIONS 表)ALTER TABLE t ADD CONSTRAINT pk_id PRIMARY KEY (id) EXCEPTIONS INTO exceptions;
SELECT t.* FROM t, exceptions e WHERE t.rowid = e.row_id;
ALTER TABLE t ADD CONSTRAINT pk_id PRIMARY KEY (id);DISABLE 會刪除索引,ENABLE NOVALIDATE 重啟前**必須先重建索引**:CREATE UNIQUE INDEX pk_id ON t(id);DBMS_REDEFINITION 線上重組,避免長時間鎖表CREATE TABLE sales (
sale_id NUMBER, sale_date DATE, amount NUMBER
) PARTITION BY RANGE (sale_date) (
PARTITION p_2023_q1 VALUES LESS THAN (DATE '2023-04-01') TABLESPACE ts_2023_q1,
PARTITION p_2023_q2 VALUES LESS THAN (DATE '2023-07-01') TABLESPACE ts_2023_q2,
PARTITION p_max VALUES LESS THAN (MAXVALUE) TABLESPACE ts_max
);
ALTER TABLE sales ADD PARTITION p_2023_q3 VALUES LESS THAN (DATE '2023-10-01') TABLESPACE ts_2023_q3;ALTER TABLE sales DROP PARTITION p_2023_q1;(瞬間完成,資料連同索引一起刪除)CREATE TABLE orders (
order_id NUMBER, cust_id NUMBER, ...
) PARTITION BY HASH (cust_id)
PARTITIONS 16
STORE IN (ts_01, ts_02, ts_03, ts_04);
ALTER TABLE orders ADD PARTITION p_new TABLESPACE ts_05;ALTER TABLE orders COALESCE PARTITION;(減少 1 個分區,資料重新雜湊分佈)CREATE TABLE regions (
region_id NUMBER, country_code VARCHAR2(2), ...
) PARTITION BY LIST (country_code) (
PARTITION p_asia VALUES ('CN','JP','KR','TW','HK') TABLESPACE ts_asia,
PARTITION p_eu VALUES ('DE','FR','IT','ES') TABLESPACE ts_eu,
PARTITION p_other VALUES (DEFAULT) TABLESPACE ts_other
);
p_other,插入 'XX' 報錯 ORA-14400ALTER TABLE regions MODIFY PARTITION p_asia ADD VALUES ('SG','MY');CREATE TABLE logs (
log_id NUMBER, log_date DATE, source_id NUMBER, msg VARCHAR2(4000)
) PARTITION BY RANGE (log_date)
SUBPARTITION BY HASH (source_id) SUBPARTITIONS 8
STORE IN (ts_log_01, ts_log_02, ts_log_03, ts_log_04) (
PARTITION p_2024_01 VALUES LESS THAN (DATE '2024-02-01'),
PARTITION p_2024_02 VALUES LESS THAN (DATE '2024-03-01')
);
SELECT * FROM logs PARTITION (p_2024_01); 或 SUBPARTITION (p_2024_01_SYS_SUBP1);CREATE TABLE sales_fact (
sale_id NUMBER, sale_date DATE, region_id NUMBER, amount NUMBER
) PARTITION BY RANGE (sale_date)
SUBPARTITION BY LIST (region_id) (
PARTITION p_2024_q1 VALUES LESS THAN (DATE '2024-04-01') (
SUBPARTITION p_2024_q1_asia VALUES (1,2,3) TABLESPACE ts_asia,
SUBPARTITION p_2024_q1_eu VALUES (4,5,6) TABLESPACE ts_eu
),
PARTITION p_2024_q2 VALUES LESS THAN (DATE '2024-07-01') (
SUBPARTITION p_2024_q2_asia VALUES (1,2,3) TABLESPACE ts_asia,
SUBPARTITION p_2024_q2_eu VALUES (4,5,6) TABLESPACE ts_eu
)
);
| 操作 | 語法範例 | 說明 |
|---|---|---|
| 交換分區(載入/歸檔神技) | ALTER TABLE sales EXCHANGE PARTITION p_2023_q1 WITH TABLE sales_staging INCLUDING INDEXES WITHOUT VALIDATION; | 瞬間切換段指標,零資料移動,需結構完全一致 |
| 截斷分區 | ALTER TABLE sales TRUNCATE PARTITION p_2023_q1 DROP STORAGE; | 保留分區定義,釋放空間 |
| 重命名分區 | ALTER TABLE sales RENAME PARTITION p_old TO p_new; | 僅修改字典 |
| 合併分區 | ALTER TABLE sales MERGE PARTITIONS p_2023_q1, p_2023_q2 INTO PARTITION p_2023_h1; | 資料合併,索引重建 |
| 移動分區(跨表空間/壓縮) | ALTER TABLE sales MOVE PARTITION p_2023_q1 TABLESPACE ts_archive COMPRESS FOR OLTP UPDATE INDEXES; | 12c+ UPDATE INDEXES 同步維護全域索引 |
| 修改列表值 | ALTER TABLE regions MODIFY PARTITION p_asia ADD VALUES ('VN');ALTER TABLE regions MODIFY PARTITION p_asia DROP VALUES ('HK'); | 列表/子分區專用 |
-- 約束
SELECT * FROM user_constraints WHERE table_name = 'T';
SELECT * FROM user_cons_columns WHERE table_name = 'T';
-- 分區表
SELECT * FROM user_part_tables WHERE table_name = 'SALES';
SELECT * FROM user_tab_partitions WHERE table_name = 'SALES';
SELECT * FROM user_tab_subpartitions WHERE table_name = 'SALES';
SELECT * FROM user_part_key_columns WHERE name = 'SALES';
SELECT * FROM user_subpart_key_columns WHERE name = 'SALES';
-- 分區索引
SELECT * FROM user_part_indexes WHERE table_name = 'SALES';
SELECT * FROM user_ind_partitions WHERE index_name = 'IDX_SALES_DT';
ENABLE NOVALIDATE 後忘記重建索引導致無法 ENABLE VALIDATESUBPARTITION TEMPLATE 簡化組合分區 DDL約束保障資料正確,分區賦能大資料高效。兩者結合的核心原則:約束設計服從分區策略,分區維護利用約束狀態切換。建立標準化 DDL 模板、維護 Runbook、定期巡檢腳本,讓複雜度可控、可傳承。