測試環境
- 軟體:Windows 2000 + Oracle 9i
- 硬體:CPU 1.8GHz + RAM 512MB
測試資料
-- T2 小表 5000 筆
CREATE TABLE T2 AS SELECT ROWNUM ID, a.* FROM ALL_OBJECTS a WHERE 1=0;
ALTER TABLE T2 ADD CONSTRAINT T2_PK_ID PRIMARY KEY (ID);
INSERT /*+ APPEND */ INTO T2 SELECT ROWNUM ID, a.* FROM ALL_OBJECTS a WHERE ROWNUM <= 5000;
-- T1 大表 10000 筆
CREATE TABLE T1 AS SELECT ROWNUM SID, T2.* FROM T2 WHERE 1=0;
四種更新方法
| 方法 | 語法範例 | 特點 |
| 1. 相關子查詢 |
UPDATE T1 SET col = (SELECT col FROM T2 WHERE T2.ID = T1.T1_FK_ID); |
直觀易寫,但每列執行子查詢,大表效能差 |
| 2. MERGE 陳述式 |
MERGE INTO T1 USING T2 ON (T1.T1_FK_ID = T2.ID) WHEN MATCHED THEN UPDATE SET T1.col = T2.col; |
單一陳述式完成,優化器可選擇 Hash Join,效能佳 |
| 3. PL/SQL 批次處理 |
FORALL i IN 1..cnt UPDATE T1 SET col = vals(i) WHERE id = ids(i); |
減少 Context Switch,適合應用層批次 |
| 4. 並行 DML (PDML) |
ALTER SESSION ENABLE PARALLEL DML; UPDATE /*+ PARALLEL(T1,4) */ T1 SET col = (SELECT col FROM T2 WHERE T2.ID = T1.T1_FK_ID); |
利用多 CPU 並行,大表顯著加速,需 Enterprise Edition |
實測結果摘要(原文未提供完整數據,以下為典型趨勢)
- 小資料量(<1萬筆):相關子查詢與 MERGE 差異不明顯。
- 中大資料量(>10萬筆):MERGE > 並行 DML > PL/SQL 批次 > 相關子查詢。
- 索引影響:T1.FK_ID 與 T2.PK_ID 均有索引時,MERGE 多採用 Nested Loop;無索引時改 Hash Join,效能更穩定。
最佳實務建議
- 優先使用 MERGE,語法標準、可讀性高、優化器支援完善。
- 超大量更新(百萬級以上)考慮 Parallel DML 搭配適當並行度。
- 應用程式層批次更新採用 FORALL + BULK COLLECT,減少網路往返。
- 更新前分析執行計畫,確認 Join 方式與索引使用;必要時加 Hint 強制 Hash Join。
- 大量更新建議分批 Commit(如每 5000 筆),避免 Undo 爆滿與鎖競爭。