CREATE GLOBAL TEMPORARY TABLE 必须指定 ON COMMIT 子句,否则报 ORA-14450 错误;支持 ON COMMIT DELETE ROWS(事务级)和 PRESERVE ROWS(会话级)两种数据生命周期模式。
CREATE GLOBAL TEMPORARY TABLE 语法必须带 ON COMMIT 子句
不写 on commit 会直接报错:ora-14450: attempt to access a transaction-specific temporary table already in use。oracle 强制要求声明数据生命周期——是随事务结束就清空(on commit delete rows),还是保留到会话结束(on commit preserve rows)。
常见误操作:照着普通表语法写,漏掉子句,或写成 ON COMMIT DROP(不存在这种写法)。
-
ON COMMIT DELETE ROWS:适合中间计算、校验逻辑,事务一提交,数据自动消失,不同事务互不干扰 -
ON COMMIT PRESERVE ROWS:适合会话内多次交互场景,比如 Web 应用一个用户连接复用多次查询,但注意:会话没断开,数据一直占内存,可能被后续 SQL 无意读到 - 两种模式下,表结构本身永久存在,只是数据隔离;
TRUNCATE对 GTT 有效,但DROP TABLE需要CREATE ANY TABLE权限,一般不用
INSERT / SELECT 操作 GTT 时要注意会话隔离性
GTT 数据天然按会话隔离,同一张 temp_orders 表,用户 A 插入 10 行,用户 B 查不到——这是设计特性,不是 bug。但容易踩坑的地方在于:开发时在单个 SQL*Plus 窗口反复测试,误以为“数据还在”就是正常,上线后多用户并发才发现逻辑错乱。
典型错误现象:SELECT COUNT(*) FROM temp_orders 在事务中返回 0,是因为上一个事务已提交且用了 ON COMMIT DELETE ROWS;或者查到了“旧数据”,其实是上个未退出的会话残留。
- 测试阶段建议显式加
COMMIT或ROLLBACK,再查,避免会话状态干扰判断 - 不要在存储过程中依赖 GTT 的“跨事务残留”,除非明确用了
PRESERVE ROWS且确认会话生命周期可控 - GTT 不支持外键、唯一约束(除主键外)、索引需手动建;如果忘了建索引,
JOIN大量数据时性能骤降,但错误不会报出来
DBA_TEMP_FILES 和 PGA 内存影响常被忽略
GTT 数据默认走临时表空间(DBA_TEMP_FILES),但小数据量时 Oracle 可能直接在 PGA 中缓存。这意味着:表面看没动磁盘,实际内存压力已上升;一旦 PGA 不足,会话可能报 ORA-04030: out of process memory,而不是临时表空间满的错误。
尤其当 GTT 字段含 VARCHAR2(4000) 或 CLOB,即使只插 100 行,也可能触发大量内存分配。
- 监控可用:
SELECT * FROM V$TEMPSEG_USAGE查当前会话临时段使用情况 - 建表时尽量控制字段长度,避免无意义的
VARCHAR2(4000);数字用NUMBER而非VARCHAR2存储 - 不用时及时
DELETE FROM temp_table或TRUNCATE TABLE temp_table,TRUNCATE更快且不产生回滚日志
PL/SQL 匿名块里不能直接 CREATE GTT
想在存储过程或匿名块里动态建 GTT?不行。CREATE GLOBAL TEMPORARY TABLE 是 DDL,PL/SQL 默认不允许执行 DDL(除非用 EXECUTE IMMEDIATE),而且即便绕过去,也违背 GTT 的设计初衷——它本该是预定义结构,供多个过程复用。
常见错误尝试:BEGIN CREATE GLOBAL TEMPORARY TABLE ... → 直接编译失败,报 PLS-00103。
- 正确做法:提前用 SQL*Plus 或工具建好 GTT,权限开放给应用用户
- 如果真需要动态结构,考虑用嵌套表(
TYPE ... IS TABLE OF ...)或集合,在内存中操作,不落地 - GTT 不支持
ALTER TABLE ... ADD COLUMN,字段增减必须重建表,所以初始设计要留余量
GTT 的“临时”只针对数据,结构是永久的;真正难调试的,往往是那个没写 ON COMMIT 的建表语句,和以为“数据该还在”的逻辑假设。










