Oracle全局临时表中的保存点

Oracle全局临时表中的保存点,oracle,oracle11g,temp-tables,savepoints,Oracle,Oracle11g,Temp Tables,Savepoints,我了解到Oracle全局临时表中的保存点会删除所有数据,但当我在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

我了解到Oracle全局临时表中的保存点会删除所有数据,但当我在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>
对于具有事务范围的表,结果相同:

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在您放入内容时会延迟分配存储(会话的临时段),并且在处理完数据时(在会话结束时,或在事务结束时,取决于类型),它可以释放存储,而不是单独删除行,就像截断普通表时发生的情况一样

我很想知道,如果在放入任何数据之前有一个保存点,并回滚到该保存点,会发生什么情况-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
这很重要的原因是,当您执行正常的删除操作(而不是截断操作)时,表的任何完整扫描仍然必须筛选所有数据块,以查看它们是否包含任何数据。如果在以前某个时间表中有大量数据,那么针对空表的DML可能会导致大量I/O

我正试图加快一些代码的运行速度——它将一些内容作为草稿插入一个临时表中,部分原因是它可以连接到一个永久表,并将结果返回给它的调用者。临时表仅用于此例程,因此在例程结束时可以安全地将其清除,但它可能在父事务中被多次调用,因此我无法截断(
truncate
是DDL,因此提交事务),但我也无法将其清除,或同一事务中的调用将拾取彼此的行。通过DELETE进行清除会造成相当大的开销,特别是因为表上没有索引,所以针对它进行选择将始终是完全扫描

我正在探索的选项是在例程开始时使用
保存点
,执行临时工作,然后在返回结果之前回滚到保存点。另一种选择可能是将例程放在自治事务中,但这意味着将C代码移植到PL/SQL存储过程中,如果临时表需要连接到调用方插入的未提交数据,则无论如何都无法工作

请注意,我是在12c中进行研究的——本版本中对临时表进行了一些改进(请参阅),但我认为这不会影响wrt保存点的行为