全域暫存表 (Global Temporary Table, GTT) 讓多會話共享表結構、隔離數據,無需手動清理,是複雜報表、ETL 中轉、多步驟業務邏輯的利器。本文系統梳理兩種保留模式、動態建表範例、統計資訊陷阱與最佳實踐。
| 特性 | 會話級 ON COMMIT PRESERVE ROWS | 事務級 ON COMMIT DELETE ROWS |
|---|---|---|
| 數據可見性 | 僅當前會話可見 | 僅當前會話可見 |
| 提交行為 | 保留,斷開會話才截斷 | 刪除,每次 COMMIT 截斷 |
| 適用場景 | 跨多事務的臨時集合(如購物車、多步精靈) | 單事務內中間結果(如複雜報表分步聚合) |
| 建表語法 | CREATE GLOBAL TEMPORARY TABLE gtt_session (...) ON COMMIT PRESERVE ROWS; | CREATE GLOBAL TEMPORARY TABLE gtt_txn (...) ON COMMIT DELETE ROWS; |
CREATE OR REPLACE PROCEDURE proc_temp_demo (
p_col1 VARCHAR2,
p_col2 VARCHAR2
) AS
v_cnt NUMBER;
v_sql VARCHAR2(1000);
BEGIN
-- 1. 若不存在則動態建表(事務級)
SELECT COUNT(*) INTO v_cnt FROM user_tables WHERE table_name = 'T_TEMP';
IF v_cnt = 0 THEN
EXECUTE IMMEDIATE q'[
CREATE GLOBAL TEMPORARY TABLE t_temp (
col1 VARCHAR2(10),
col2 VARCHAR2(10)
) ON COMMIT DELETE ROWS
]';
END IF;
-- 2. 插入測試數據
EXECUTE IMMEDIATE 'INSERT INTO t_temp VALUES (:1, :2)' USING p_col1, p_col2;
-- 3. 驗證隔離性:同會話可讀
EXECUTE IMMEDIATE 'SELECT col1 FROM t_temp' INTO v_cnt;
DBMS_OUTPUT.PUT_LINE('Inserted col1: ' || v_cnt);
-- 4. 手動清理(事務級其實 COMMIT 即自動清)
EXECUTE IMMEDIATE 'DELETE FROM t_temp';
COMMIT;
-- 5. 演示結束可選擇 DROP(生產慎用,DDL 會產生硬解析)
-- EXECUTE IMMEDIATE 'DROP TABLE t_temp';
END;
/
問題:GTT 無持久統計資訊,優化器常用「預設選擇率」導致執行計劃偏差(如全表掃描 vs 索引)。
解決 (11g+):
-- 會話級鎖定統計資訊
EXEC DBMS_STATS.SET_TABLE_STATS(ownname=>USER, tabname=>'GTT_SESSION', numrows=>10000, numblks=>200);
-- 或啟用動態採樣
ALTER SESSION SET OPTIMIZER_DYNAMIC_SAMPLING = 4;
12c+ 可用 GLOBAL_TEMP_TABLE_STATS 偏好參數自動管理。
| 指標 | 永久表 + 手動 DELETE | GTT (事務級) |
|---|---|---|
| Redo 產生量 | 高(完整記錄) | 極低(僅 Undo 元數據) |
| Undo 保留壓力 | 大 | 小 |
| High Water Mark 移動 | 頻繁 | 不移動(截斷重置) |
| 並發鎖衝突 | 可能 | 無(會話私有) |
EXPDP 不導出 GTT 數據(結構可導)CREATE TABLE 權限,DROP ANY TABLE 可刪除他人 GTT 結構GTT 以「結構共享、數據隔離、零 Redo、自動清理」四大特性,完美契合臨時中間結果場景。**選型原則**:跨事務用會話級、單事務用事務級;生產環境優先靜態建表、配合動態採樣解決統計資訊問題;連接池場景務必加清理邏輯。