跨資料庫遷移主從表 (父子表/外鍵關聯) 時,IMPORT 會檢查參照完整性導致失敗,LOAD 雖可繞過檢查但留下「檢查暫掛」狀態導致後續查詢報錯。本文提供經驗證的標準化解決方案:先導父表、後導子表、統一 SET INTEGRITY。
CREATE TABLE PARENTT (
ID INT NOT NULL,
NAME CHAR(20) NOT NULL,
CONSTRAINT P_PT PRIMARY KEY (ID)
);
CREATE TABLE CHILDT (
ID INT NOT NULL,
CNAME CHAR(40) NOT NULL,
PID INT,
CONSTRAINT P_CT PRIMARY KEY (ID),
CONSTRAINT F_CT FOREIGN KEY (PID) REFERENCES PARENTT (ID) ON DELETE CASCADE
);
db2 "IMPORT FROM child.del OF DEL INSERT INTO CHILDT"
SQL0530N FOREIGN KEY "F_CT" - 插入值不等於父表任何父鍵值。
原因: IMPORT 逐行執行,即時檢查外鍵約束。
db2 "LOAD FROM child.del OF DEL INSERT INTO CHILDT" -- 成功
db2 "SELECT * FROM CHILDT"
SQL0668N 不允許對表 "CHILDT" 執行操作,原因碼 "1" (檢查暫掛狀態)
原因: LOAD 繞過約束檢查,但將表標記為「檢查暫掛」(Set Integrity Pending),必須手動驗證才能解除。
db2 "SET INTEGRITY FOR CHILDT IMMEDIATE CHECKED" -- 成功解除
痛點: 大量主從表逐個執行 SET INTEGRITY 耗時極長,且順序錯誤會報 SQL0530N。
db2 "SELECT
SUBSTR(REFTABSCHEMA,1,20) AS PARENT_SCHEMA,
SUBSTR(REFTABNAME,1,30) AS PARENT_TABLE,
SUBSTR(TABSCHEMA,1,20) AS CHILD_SCHEMA,
SUBSTR(TABNAME,1,30) AS CHILD_TABLE
FROM SYSCAT.REFERENCES"
PARENT_SCHEMA PARENT_TABLE CHILD_SCHEMA CHILD_TABLE -------------- ----------------------- ------------ ------------ HDK PARENTT HDK CHILDT ASN_DOWN_TC_M6101 IBMQREP_SENDQUEUES ASN_DOWN_TC_M6101 IBMQREP_SUBS ASN_DOWN_TC_M6101 IBMQREP_SUBS ASN_DOWN_TC_M6101 IBMQREP_SRC_COLS
import collections
def get_load_order(fk_relations):
"""依據外鍵關係拓撲排序,返回載入順序列表"""
graph = collections.defaultdict(set)
indegree = collections.defaultdict(int)
all_tables = set()
for parent_schema, parent_table, child_schema, child_table in fk_relations:
parent = f"{parent_schema}.{parent_table}"
child = f"{child_schema}.{child_table}"
graph[parent].add(child)
indegree[child] += 1
all_tables.add(parent)
all_tables.add(child)
# Kahn 演算法
queue = collections.deque([t for t in all_tables if indegree[t] == 0])
order = []
while queue:
table = queue.popleft()
order.append(table)
for child in graph[table]:
indegree[child] -= 1
if indegree[child] == 0:
queue.append(child)
if len(order) != len(all_tables):
raise Exception("循環依賴檢測失敗")
return order
# 載入順序:PARENTT → CHILDT
# 生成腳本:
db2 "LOAD FROM parentt.ixf OF IXF REPLACE INTO HDK.PARENTT COPY NO WITHOUT PROMPTING"
db2 "LOAD FROM childt.ixf OF IXF REPLACE INTO HDK.CHILDT COPY NO WITHOUT PROMPTING"
# 統一解除檢查暫掛 (按反向拓撲序:子表優先)
db2 "SET INTEGRITY FOR HDK.CHILDT IMMEDIATE CHECKED"
db2 "SET INTEGRITY FOR HDK.PARENTT IMMEDIATE CHECKED" -- 父表通常無檢查暫掛,保險起見執行
#!/bin/bash
# DB2 主從表大數據遷移標準化腳本
SRC_DB=src_db
TGT_DB=tgt_db
SCHEMA=HDK
EXPORT_DIR=/db2export/$SCHEMA
LOAD_DIR=/db2load/$SCHEMA
# 1. 導出結構與數據
db2look -d $SRC_DB -z $SCHEMA -e -o $EXPORT_DIR/schema.ddl
db2move $SRC_DB EXPORT -u user -p pwd -sn $SCHEMA -l $EXPORT_DIR
# 2. 目標庫建立結構 (可修改 DDL 調整表空間等)
db2 -tvf $EXPORT_DIR/schema.ddl
# 3. 獲取外鍵依賴並拓撲排序 (呼叫 Python 腳本)
LOAD_ORDER=$(python3 get_load_order.py $TGT_DB $SCHEMA)
# 4. 按順序並行 LOAD (分批次,每批 5-10 張表)
for batch in $(split_batches "$LOAD_ORDER" 8); do
for table in $batch; do
db2 "LOAD FROM $LOAD_DIR/${table}.ixf OF IXF REPLACE INTO $table COPY NO WITHOUT PROMPTING" &
done
wait # 等待當前批次完成
done
# 5. 按反向順序統一 SET INTEGRITY
REVERSE_ORDER=$(echo "$LOAD_ORDER" | tac)
for table in $REVERSE_ORDER; do
db2 "SET INTEGRITY FOR $table IMMEDIATE CHECKED"
done
# 6. 統計更新
db2 "CALL SYSPROC.ADMIN_CMD('RUNSTATS ON TABLE ALL')"
| 項目 | 建議 | 理由 |
|---|---|---|
| 檔案格式 | IXF | 二進制、自描述、LOAD 直讀、支援 LOB/XML |
| LOAD 模式 | REPLACE INTO | 截斷表重載,避免重複鍵衝突 |
| COPY NO | 啟用 | 不產生複製映像,大幅提速 |
| WITHOUT PROMPTING | 啟用 | 無人值守自動化 |
| 並行批次大小 | CPU 核心數 / 表空間容器數 | 平衡並行度與資源競爭 |
| SET INTEGRITY 順序 | 子表優先 (反向拓撲序) | 父表驗證需子表數據就緒 |
| 大表分區載入 | 分區級並行 LOAD | 利用 DPF 並行度 |
| 錯誤 | 原因 | 解決 |
|---|---|---|
| SQL0530N 導入子表失敗 | 父表未先載入 | 嚴格按拓撲序載入 |
| SQL0668N 原因碼 1 | 檢查暫掛未解除 | 執行 SET INTEGRITY IMMEDIATE CHECKED |
| SET INTEGRITY 耗時極長 | 大表全量掃描驗證 | 分區表並行驗證、確保索引存在、考慮 INCREMENTAL |
| 循環外鍵依賴 | 互相引用 (A→B, B→A) | 暫時停用約束載入,載入後重建 |
主從表遷移的核心難點在於外鍵約束的時序協調。透過系統視圖自動發現依賴、拓撲排序決定載入順序、批次並行 LOAD、統一反向 SET INTEGRITY,可將「人工逐表操作」轉化為「全自動化流水線」,實現大規模主從表遷移的零失誤、高效率、可重複交付。