ADG备库无法创建全局临时表,因其处于OPEN READ ONLY模式,禁止所有DDL操作;GTT定义不通过redo同步,主库创建的GTT在备库不存在;唯一可行场景是报表必须在主库执行且资源允许时谨慎使用。

在Oracle 19c ADG(Active Data Guard)环境中,全局临时表(GTT)**不能跨主库与备库共享数据,也不能用于替代物化视图做查询重写加速**——它只在当前会话本地生效,且ADG备库默认为只读,CREATE GLOBAL TEMPORARY TABLE语句本身在备库上会报错或被跳过。想靠GTT“加速报表”却忽略ADG的只读约束和会话隔离性,是典型误用。
为什么ADG备库上建不了全局临时表?
ADG备库处于OPEN READ ONLY模式,所有DDL操作(包括CREATE GLOBAL TEMPORARY TABLE)均被禁止。即使你在主库创建了GTT,它的定义也不会同步到备库(因为GTT结构不走redo传输),更不会自动重建。常见错误是开发在主库测试通过后直接切到备库执行报表SQL,结果遇到:
ORA-16000: database open for read-only access-
ORA-01031: insufficient privileges(即使有DBA权限,只读库也不允许DDL)
根本原因不是权限不足,而是ADG架构设计上就禁用写入类操作。别试图绕过——ALTER DATABASE OPEN READ WRITE会彻底破坏ADG保护机制。
ADG环境下GTT的唯一可行用法
仅当报表逻辑**必须在主库执行**(比如需要实时写中间状态、触发业务流程),且你已确认主库资源可承受额外负载时,GTT才可谨慎使用。此时注意三点:
- 必须显式指定
ON COMMIT DELETE ROWS或ON COMMIT PRESERVE ROWS,避免会话残留数据干扰后续查询 - GTT中不能引用备库不可见的对象(如未同步的私有同义词、主库专用包函数)
- 若报表SQL含绑定变量,GTT列类型必须与绑定变量类型严格一致,否则可能触发隐式转换导致索引失效或全表扫描
示例:主库上统计当日订单分区域汇总,再关联维度表出报表
CREATE GLOBAL TEMPORARY TABLE temp_daily_region AS SELECT region_id, COUNT(*) cnt, SUM(amount) amt FROM orders WHERE order_date = TRUNC(SYSDATE) GROUP BY region_id ON COMMIT DELETE ROWS; SELECT r.name, t.cnt, t.amt FROM regions r JOIN temp_daily_region t ON r.id = t.region_id;
比GTT更适配ADG的替代方案
ADG的核心价值是分担主库查询压力,因此优化方向应是“让备库高效跑报表”,而非强行在主库塞GTT。推荐组合:
- 在备库启用
QUERY_REWRITE_ENABLED = TRUE,配合主库同步过来的物化视图(MV)——但注意MV需在主库创建并刷新,ADG会自动同步MV定义和数据(只要ENABLE QUERY REWRITE且基表有RELY约束) - 对高频聚合报表,用
WITH子句+物化提示/*+ materialize */,强制优化器缓存中间结果到临时表空间(非GTT),该方式在ADG只读库完全合法 - 分区表+分区裁剪:将大事实表按时间分区,报表加
WHERE time_id >= TRUNC(SYSDATE-7),ADG能自动跳过无关分区,避免全表扫描
关键点在于:ADG不支持GTT跨库,但支持所有只读SQL执行路径的优化。把精力放在物化视图匹配、分区策略、以及/*+ materialize */这类无副作用的提示上,比纠结GTT更实际。
最易被忽略的是:ADG备库的temp_tablespace如果配置过小,WITH子句或排序操作会频繁触发磁盘临时段,反而拖慢报表——这比GTT缺失更值得优先排查。


















