Oracle全局临时表中的保存点



我阅读了Oracle Global临时表中的保存点删除所有数据,但是当我在Oracle 11G上测试时,它们像堆一样工作。有人可以解释吗?

insert into table_1 values('one');
insert into table_1 values('two');
savepoint f1;
insert into table_1 values('three');
insert into table_1 values('four');
rollback to f1;
-- the records in table are 2 records just like heap tables, but I read that
-- savepoints in GTT truncates all the data

您在哪里阅读了此?我怀疑没有在Oracle SQL参考中。因此,解释很简单:该断言的作者尚未测试全球临时表的行为。要么是您正在阅读其他一些SQL实现的描述,例如Derbydb。

为了完整,让我们排除交易或会话范围的作用。这是两个全球临时表:

create global temporary table gtt1
   ( col1 varchar2(30) )
   ON COMMIT PRESERVE ROWS 
/
create global temporary table gtt2
   ( col1 varchar2(30) )
   ON COMMIT DELETE ROWS 
/

让我们为会话范围的一个实验运行您的实验:

SQL> insert into gtt1 values('one');
1 row created.
SQL> insert into gtt1 values('two');
1 row created.
SQL> savepoint f1;
Savepoint created.
SQL> insert into gtt1 values('three');
1 row created.
SQL> insert into gtt1 values('four');
1 row created.
SQL> rollback to f1;
Rollback complete.
SQL> select * from gtt1;
COL1
------------------------------
one
two
SQL> 

具有交易范围的表的相同结果:

SQL> insert into gtt2 values('five');
1 row created.
SQL> insert into gtt2 values('six');
1 row created.
SQL> savepoint f2;
Savepoint created.
SQL> insert into gtt2 values('seven');
1 row created.
SQL> insert into gtt2 values('eight');
1 row created.
SQL> rollback to f2;
Rollback complete.
SQL> select * from gtt2;
COL1
------------------------------
five
six
SQL>

实际上这不足为奇。Oracle官方文件指出:

"临时表定义的持续方式与常规表的定义相同"

基本上它们堆表。差异是:

  • 数据的范围(可见性)
  • 用于持久数据的表空间(全局临时表写入临时表空间)。

我认为您误会了 - 如果您回滚到保存点,则Oracle应该在保存点之后撤消所有完成的工作(同时仍保留在保存点之前完成的任何未承诺的工作)。/p>

对于临时表,Oracle懒惰地分配存储(您的会话的临时段),然后将其放入内容时(在会话结束时或交易结束时数据完成时),取决于类型),它可以简单地对存储进行处理,而不是单独删除行,就像您在截断普通表时发生的事情一样。

我有兴趣找出如果您在之前有一个保存点发生的情况,然后将任何数据放入其中,然后返回该保存点 - 将oracle分解为存储空间,否则它会保留存储空间并删除。从其中的行?

事实证明前者的行为就像截断。

SAVEPOINT f0;
SELECT * FROM v$tempseg_usage; -- Should show nothing for your session
insert into table_1 values('one');
insert into table_1 values('two');
SELECT * FROM v$tempseg_usage; -- Should show a DATA row for your session
savepoint f1;
insert into table_1 values('three');
insert into table_1 values('four');
rollback to f1; -- Undo three and four but preserve one and two
SELECT * FROM v$tempseg_usage; -- Still shows a DATA row for your session
rollback to f0; -- Undo all the inserts
SELECT * FROM v$tempseg_usage; -- row for your session has gone

这很重要的原因是,当您进行普通删除时 - 而不是截断时 - 那么表的任何完整扫描仍然必须筛选所有数据块,以查看它们是否在。空表可能会产生大量I/O ,如果表格之前有很多数据!

我正在试图加快做到这一点的一些代码 - 它将某些东西作为暂时的表作为刮擦板,部分原因是它可以将其送到永久表中,并将结果返回给呼叫者。临时表仅对此例程的好处,因此可以安全地将其清除在例程结束时,但是在父交易中可能被称为多次,因此我无法截断(TRUNCATE是DDL,所以进行交易),但我也无法将其清除,或者在同一交易中的调用会捡起一行的行。通过删除清除会导致很多开销,尤其是因为桌子上没有索引,因此选择始终会进行全面扫描。

我正在探索的选项是在例程开始时拥有一个SAVEPOINT,进行临时工作,然后在返回结果之前回到保存点。另一个选项可能是将例程放入自主交易中,但这意味着将C代码移植到PL/SQL存储过程中,并且如果需要连接临时表以将临时表连接到呼叫者插入的未订阅数据,则无效。

请注意,我在12C中进行了研究 - 在此版本中,临时表有一些改进(请参阅https://oracle-base.com/articles/misc/misc/temporary-tables),但我不认为影响行为wrt保存点。

最新更新