Oracle 全局临时表 GTT 是什么?ON COMMIT DELETE ROWS 和 PRESERVE ROWS 有什么区别?
简化版
Oracle 全局临时表的表结构是全局持久的,但数据是会话或事务私有的。ON COMMIT DELETE ROWS 表示提交后清空当前事务数据,ON COMMIT PRESERVE ROWS 表示数据保留到会话结束。
详细版
GTT 常用于批处理、报表中间结果、复杂过程拆分。多个会话看到同一张临时表结构,但各自的数据互相隔离。
示例:
CREATE GLOBAL TEMPORARY TABLE tmp_order_ids (
order_id NUMBER
) ON COMMIT DELETE ROWS;
它不是普通表,也不是每次自动创建的表。使用时要注意提交时机、索引、统计信息、连接池复用和临时表空间压力。
完整版教学
一、GTT 的“全局”和“临时”分别指什么
“全局”指表定义对数据库可见,创建一次后对象结构一直存在;“临时”指表里的数据是临时的,并且对会话或事务隔离。
这和很多人理解的“临时表就是临时创建一张表”不同。Oracle GTT 不是每次用完就 drop 表结构。
表结构:全局共享
表数据:会话/事务私有
二、两种 ON COMMIT 模式
ON COMMIT DELETE ROWS 在事务提交时清空当前会话在表里的数据;ON COMMIT PRESERVE ROWS 则保留到会话结束。
CREATE GLOBAL TEMPORARY TABLE tmp_a(id NUMBER)
ON COMMIT DELETE ROWS;
CREATE GLOBAL TEMPORARY TABLE tmp_b(id NUMBER)
ON COMMIT PRESERVE ROWS;
前者适合事务内中间数据,后者适合同一会话内多步骤处理。
三、为什么连接池场景要小心
应用连接池会复用数据库会话。如果使用 PRESERVE ROWS,数据可能保留到会话结束,而连接池里的会话并不一定随请求结束而关闭。
这就可能出现请求 A 写入临时数据,请求 B 复用同一连接时看到残留数据的风险。虽然通常会通过清理避免,但设计时必须意识到会话生命周期。
因此 Web 应用里更常用 ON COMMIT DELETE ROWS,或每次使用前显式清理。
四、GTT 的性能和空间
GTT 数据通常使用临时段,减少对普通业务表的影响。它适合大批量中间结果,而不是把小逻辑都拆到临时表里。
如果一次任务写入 500 万行临时数据,临时表空间也会承压。还要考虑临时表上的索引维护成本。
| 场景 | 是否适合 GTT | 原因 |
|---|---|---|
| 批量中间结果 | 适合 | 简化 SQL 和过程 |
| 请求级小变量 | 不适合 | 过度设计 |
| 跨请求状态 | 不适合 | 会话复用风险 |
| 报表预聚合 | 适合 | 中间集合清晰 |
五、统计信息和执行计划
GTT 也可能涉及执行计划。不同会话写入数据量差异很大时,统计信息不准确可能导致计划不稳定。
例如有的任务写 100 行,有的任务写 100 万行,同一 SQL 的最优计划不同。需要结合 Oracle 版本、动态采样和统计策略处理。
这也是 GTT 面试题容易深入的地方:它不是只会创建表,还涉及执行计划和临时空间管理。
六、常见误区与追问
- 误区:GTT 的表结构也是临时的。 表结构是持久对象,临时的是会话或事务数据。
- 误区:PRESERVE ROWS 在请求结束就清空。 它保留到会话结束,连接池复用时要小心。
- 误区:GTT 不占空间。 大量数据会占用临时表空间,并可能维护索引。
- 追问:两种 ON COMMIT 怎么选? 事务内中间结果用 DELETE ROWS,会话多步骤用 PRESERVE ROWS。
- 追问:多个会话会互相看到数据吗? 不会,数据是会话私有的。
七、加强记忆
记忆钩子:GTT 像公司共用白板模板,白板框架大家都看得到,但每个会议室写的内容只在自己房间里。
回答这题要同时讲结构持久、数据私有、提交清理模式、连接池和临时空间。这样才不是只背 CREATE GLOBAL TEMPORARY TABLE。