Oracle优化神技之临时表
Oracle临时表在处理临时数据、会话数据隔离和复杂查询优化方面非常有用。
其底层逻辑是通过Oracle特殊的临时表来减少I/O操作和日志开销,提高了数据库性能和查询效率。开发者可以根据具体需求和场景,合理使用临时表来简化数据处理逻辑和提高系统性能。
早期开发人员在使用Oracle数据库时,经常因为不熟悉或不了解全局临时表(Global Temporary Table,下文简称GTT)的特性,因而自行定义了所谓的“临时表”,不但增加了开发复杂度,比如需要自行做数据清理和会话隔离等问题,还因高频操作这类表产生了大量重做日志(redo logs),进而增加了I/O负载和系统开销,主要代价这么多,最终的应用性能还不够好。
所幸这类问题随着用户量的提升,大家口口相传这个最佳实践,后续开发已经很少会犯这类低级问题。
那是不是用了Oracle的临时表就可以高枕无忧了呢?
最近笔者在某客户遇到一个临时表的问题,在分析这个客户问题的过程,也和大家一起来回顾下有关Oracle临时表的知识。
- 1.创建临时表
- 2.临时表统计信息
- 3.临时表索引
- 4.临时表是否cache
- 5.临时表相关问题
1.创建临时表
本次遇到问题的临时表,是使用的Oracle的GTT,且定义表中数据是基于session-specific的类型,脱敏后的创建语句为:
CREATE GLOBAL TEMPORARY TABLE "JINGYU"."G_T_T1"
("ID" NUMBER(10,0) NOT NULL ENABLE,
"NAME" VARCHAR2(30) NOT NULL ENABLE)
ON COMMIT PRESERVE ROWS;
下面是官方文档截图,比较了GTT和PTT的差异:

除了上面提到的命名规则等差异之外,还要补充一点:
GTT是8i后就已经支持的技术,而PTT要在18c及以后版本才支持。
关于GTT的两种类型,文档说明如下:

根据你的应用需求选择,简单说就是如果想在事务结束就清空表,选择DELETE ROWS类型;如果想在会话结束才清空表,就选择PRESERVE ROWS类型。
2.临时表统计信息
临时表也是有统计信息的,而且临时表统计信息的机制在不同版本也有差异。
先看下在19c版本下表现:
我先在session1中插入两条测试数据,收集统计信息:
INSERT INTO G_T_T1 VALUES (1, 'Alfred');
INSERT INTO G_T_T1 VALUES (2, 'Mcdull');
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'JINGYU',
tabname => 'G_T_T1',
cascade => TRUE
);
END;
/
SELECT owner, table_name, num_rows, blocks, empty_blocks, avg_space
FROM dba_tab_statistics
WHERE table_name = 'G_T_T1';
紧接着在session2中插入一条数据,收集统计信息:
INSERT INTO G_T_T1 VALUES (3, 'Test');
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'JINGYU',
tabname => 'G_T_T1',
cascade => TRUE
);
END;
/
SELECT owner, table_name, num_rows, blocks, empty_blocks, avg_space
FROM dba_tab_statistics
WHERE table_name = 'G_T_T1';
两个查询结果是不一样的,两行结果,分别显示为2条和1条数据的统计信息。
--result1:
08:52:42 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1> SELECT owner, table_name, num_rows, blocks, empty_blocks, avg_space
FROM dba_tab_statistics
WHERE table_name = 'G_T_T1';08:53:39 2 08:53:39 3
OWNER TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE
------------------------------ ------------------------------ ---------- ---------- ------------ ----------
JINGYU G_T_T1
JINGYU G_T_T1 2 1 0 0
Elapsed: 00:00:00.02
--result2:
08:53:35 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1> SELECT owner, table_name, num_rows, blocks, empty_blocks, avg_space
FROM dba_tab_statistics
WHERE table_name = 'G_T_T1';08:53:44 2 08:53:44 3
OWNER TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE
------------------------------ ------------------------------ ---------- ---------- ------------ ----------
JINGYU G_T_T1
JINGYU G_T_T1 1 1 0 0
Elapsed: 00:00:00.01
这说明全局临时表在19c版本的默认统计信息是session级别。
--查看全局临时表的统计信息首选项设置
SELECT DBMS_STATS.GET_PREFS('GLOBAL_TEMP_TABLE_STATS', 'JINGYU', 'G_T_T1') AS global_temp_table_stats
FROM dual;
09:04:59 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1> --查看全局临时表的统计信息首选项设置
SELECT DBMS_STATS.GET_PREFS('GLOBAL_TEMP_TABLE_STATS', 'JINGYU', 'G_T_T1') AS global_temp_table_stats
FROM dual;
09:05:00 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1> 09:05:00 2
GLOBAL_TEMP_TABLE_STATS
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SESSION
Elapsed: 00:00:00.01
具体查了下文档,说是在Oracle 12c及之后的版本中,全局临时表(GTT)的统计信息确实有可能是会话级别的。这意味着每个会话可以有自己的统计信息,这与全局共享的统计信息不同。
Default in 12c is now SESSION global temporary table statistics. Consider whether your database application depends on SHARED global temporary table statistics.
而如果你的数据库还是11g版本,那么这个统计信息的机制就是不同的,也就是SHARED,这里模拟将19c的这个也修改为SHARED模式,看看表现:
BEGIN
DBMS_STATS.SET_TABLE_PREFS(
ownname => 'JINGYU',
tabname => 'G_T_T1',
pname => 'GLOBAL_TEMP_TABLE_STATS',
pvalue => 'SHARED'
);
END;
/
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'JINGYU',
tabname => 'G_T_T1',
cascade => TRUE
);
END;
/
成功修改为shared后,当表中有3条数据时收集统计信息后再次查询,会发现这个统计信息在其他会话也可以访问到:
09:10:46 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1> r
1 SELECT owner, table_name, num_rows, blocks, empty_blocks, avg_space
2 FROM dba_tab_statistics
3* WHERE table_name = 'G_T_T1'
OWNER TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE
------------------------------ ------------------------------ ---------- ---------- ------------ ----------
JINGYU G_T_T1 3 1 0 0
Elapsed: 00:00:00.02
09:10:48 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1>
3.临时表索引
GTT是可以创建索引的,当然这个索引也是临时的属性,另外还可以在GTT上创建视图和触发器。
You can create indexes for global (not private) temporary tables with the CREATE INDEX
statement. These indexes are also temporary. The data in the index has the same
session or transaction scope as the data in the temporary table. You can also create a
view or trigger on a global temporary table.
4.临时表是否cache
使用ALTER TABLE ... CACHE可以提高GTT查询性能。
ALTER TABLE G_T_T1 CACHE;
在Oracle中,通过使用ALTER TABLE ... CACHE语句可以在创建GTT时指定缓存属性。GTT是一种特殊类型的数据库表,用于存储临时数据,数据在会话结束或事务完成时被清除。CACHE关键字在这里的作用是指定GTT的缓存属性。
具体来说,CACHE关键字指示Oracle数据库将GTT的数据块缓存在内存中,而不是直接写入磁盘。这样做的好处是可以提高查询临时表数据的性能,因为访问内存通常比访问磁盘要快得多。
需要注意的是,使用CACHE会占用更多的内存空间,因为临时表的数据在会话结束或事务完成后会被清除,所以对于大型数据量或长时间运行的会话,可能需要权衡内存利用和性能。
临时表是否设置了CACHE属性是可以通过dbms_metadata.get_ddl中看到cache标识的:
select dbms_metadata.get_ddl('TABLE','G_T_T1','JINGYU') from dual;
CREATE GLOBAL TEMPORARY TABLE "JINGYU"."G_T_T1"
( "ID" NUMBER(10,0) NOT NULL ENABLE,
"NAME" VARCHAR2(30) NOT NULL ENABLE
) ON COMMIT PRESERVE ROWS
CACHE
特别需要注意的是,这个简单的cache命令,在线直接执行很可能会失败:
alter table G_T_T1 cache;
会报错ORA-14450:
14:46:14 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1> alter table G_T_T1 cache;
alter table G_T_T1 cache
*
ERROR at line 1:
ORA-14450: attempt to access a transactional temp table already in use
Elapsed: 00:00:00.02
这是因为有会话在使用GTT,确保没有使用的会话重新执行才能成功:
14:51:14 PRIMARY @DB0913_9DF_IAD -> JINGYU @DEMO1> alter table G_T_T1 cache;
Table altered.
Elapsed: 00:00:00.10
5.临时表相关问题
顺便查了一些相关问题,作为扩展供大家学习参考:
FYI:
- Performance Issue After Creating Global Temporary Table After Upgrading to 12.2 (Doc ID 2509782.1)
- How to Create Statistics on Global Temporary Tables (Doc ID 351190.1)
- https://blogs.oracle.com/optimizer/post/global-temporary-tables-and-upgrading-to-oracle-database-12c-dont-get-caught-out
Oracle优化神技之临时表的更多相关文章
- Redis 内存优化神技,小内存保存大数据
大家好,我是「码哥」,大家可以叫我靓仔. 这次码哥跟大家分享一些优化神技,当你面试或者工作中你遇到如下问题,那就使出今天学到的绝招,一招定乾坤! 如何用更少的内存保存更多的数据? 我们应该从 Redi ...
- Java调用oracle存储过程通过游标返回临时表数据
注:本文来源于 < Java调用oracle存储过程通过游标返回临时表数据 > Java调用oracle存储过程通过游标返回临时表数据 项目开发过程中,不可避免的会用到存储过程返回结 ...
- ORACLE使用GV_$TEMP_SPACE_HEADER统计临时表空使用情况不准确的问题
以前写了一篇ORACLE临时表空间总结的文章, 里面介绍了几个查看临时表空间使用情况的脚本,其中一个脚本如下所示: SELECT TU.TABLESPACE_NAME ...
- ORACLE中创建和删除临时表
CREATE GLOBAL TEMPORARY TABLE TABLENAME ( COL1 VARCHAR2(10), COL2 NUMBER) ON COMMIT PRESERVE(D ...
- Oracle 临时事务表 全局临时表_global temporary table
所有的操作都在一个事务里,事务提交后,此表清空,特别适合做插入删除频率特别高的临时表操作,比如插入完数据就开始查询,查询完就删掉等,用完就扔! 临时表分事务级临时表和会话级临时表. 事务级临时表只对当 ...
- jdbctemplate 调用oracle 有返回(会话型临时表数据的)结果的存储过程
注:本文为博主 原创. jdbctemplate 调用oracle存储过程 事务 临时表 有返回结果 1:java 代码 本逻辑代码本是想把 java 代码里的list<Strign>类 ...
- 【Oracle】恢复丢失的临时表空间文件
Oracle 11g以后,临时表空间文件是可以在重启数据库以后自动生成的(当然也可以在相同目录再建一个临时表空间文件),模拟实验如下: 1)删除临时表空间数据文件 SYS@ENMOEDU> se ...
- Oracle 计划任务批量清理临时表实例
昨天发现近一段时间,公司某oracle库数据泵方式备份比之前慢了很多,备份集大小并未增长太多.查看了下发现该用户下存在几十万张表. 一.问题分析 1.查看用户下面的表 select count(*) ...
- SQL 语句调优 where 条件 数据类型 临时表 索引
基本原则 避免全表扫描 建立索引 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理 尽量避免大事务操作,提高系统并发能力 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方 ...
- Oracle修改被占用的临时表结构
这两天在修改临时表的类型时,提示”attempt to create,alter or drop an index on temporary table already in use“的错误,由于临时 ...
随机推荐
- mmdeploy源码安装 (转换faster rcnn r50/yolox为tensorrt,并用mmdeploy sdk推理)
mmdeploy源码安装 (转换faster rcnn r50/yolox为tensorrt,并进行推理) 这个系列是一个随笔,是我走过的一些路,有些地方可能不太完善.如果有那个地方没看懂,评论区问就 ...
- 如何用一行 CSS 实现 10 种现代布局
现代 CSS 布局使开发人员只需按几下键就可以编写十分有意义且强大的样式规则.上面的讨论和接下来的帖文研究了 10 种强大的 CSS 布局,它们实现了一些非凡的工作. 01. 超级居中:place-i ...
- etcd 历史版本回溯的方法
在使用 etcd 作为配置存储或者其他的场景,如果因为误操作对其中 key 的值进行了修改,如果想要找回原来的值,可以利用 etcd 的版本机制进行回溯找回以前的值.在具体操作之前,我们首先获取一下 ...
- Flink Standalone集群部署
Flink Standalone模式部署集群是最简单的一种部署方式,不依赖于其他的组件,另外还支持YARN/Mesos/Docker等模式下的部署,这里使用的flink版本为最新的稳定版1.9.1版本 ...
- EasyNLP玩转文本摘要(新闻标题)生成
简介: 本⽂将提供关于PEGASUS的技术解读,以及如何在EasyNLP框架中使⽤与PEGASUS相关的文本摘要(新闻标题)生成模型. 作者:王明.黄俊 导读 文本生成是自然语言处理领域的一个重要研究 ...
- 五分钟学会使用 go modules(含在家办公使用技巧)
导读:go modules 是 golang 1.11 新加的特性.如今 1.13 都已经发布了第 7 个小版本了,几乎所有大项目均已开始使用,这自然也包括 Kubernetes 生态中的众多项目.笔 ...
- Sentinel 1.7.2 发布,完善开源生态及扩展性
多样化的适配模块 到目前为止,Sentinel 已覆盖微服务.API Gateway 和 Service Mesh 三大板块的核心生态,同时多语言已推出 Java.C++.Go 三种语言的原生实现. ...
- [Go] Colly 使用 POST 提交 application/x-www-form-urlencoded 示范
Colly 提供了 Post 和 PostRaw 方法,它们的参数类型不一样,需要注意. 目标地址接受指定的 Content-Type,可以通过设置 request Header. 局部代码: // ...
- IIncrementalGenerator 获取引用程序集的所有类型
本文告诉大家如何在使用 IIncrementalGenerator 进行增量的 Source Generator 生成代码时,如何获取到当前正在分析的程序集所引用的所有的程序集,以及引用的程序集里面的 ...
- WPF 让窗口激活作为前台最上层窗口的方法
在 WPF 中,如果想要使用代码控制,让某个窗口作为当前用户的输入的逻辑焦点的窗口,也就是在当前用户活动的窗口的最上层窗口,默认使用 Activate 方法,通过这个方法在大部分设备都可以做到激活窗口 ...