【问题标题】:Savepoints in Oracle global temporary tablesOracle 全局临时表中的保存点
【发布时间】:2015-05-12 17:38:13
【问题描述】:

我读到 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 oracle11g temp-tables savepoints


    【解决方案1】:

    你在哪里读到的?我怀疑不在 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>
    

    其实这并不奇怪。 official Oracle documentation 声明:

    “临时表定义的持久化方式与常规表的定义相同”

    基本上它们堆表。区别在于:

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

    【讨论】:

      【解决方案2】:

      我认为您误解了 - 如果您回滚到保存点,那么 Oracle 应该撤消保存点之后完成的所有工作(同时仍保留保存点之前完成的任何未提交的工作)。

      对于临时表,Oracle 会在您放入数据时以及在数据处理完毕时(在会话结束时或在事务结束时)延迟分配存储空间(会话的临时段) ,取决于类型)它可以只释放存储空间而不是单独删除行,就像你 TRUNCATE 一个普通表时发生的那样。

      我很想知道如果您有一个保存点任何数据被放入并回滚到该保存点会发生什么 - 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 清除会导致相当多的开销,特别是因为表上没有索引,因此对其进行选择将始终进行全扫描。

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

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

      【讨论】:

        猜你喜欢
        • 2017-10-02
        • 2023-03-27
        • 1970-01-01
        • 2016-04-02
        • 1970-01-01
        • 2012-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多