Oracle 12C新特性-临时UNDO段(Temporary Undo Segments)
在12C版本,为了减少UNDO表空间的使用率及减少REDO和归档日志的产生量,ORACLE推出了临时UNDO段(Temporary Undo Segments)新特性。这个新特性把临时表产生的UNDO信息从UNDO表空间挪到了临时表空间,这样就减少了UNDO表空间的使用。临时表的DML操作不会产生REDO日志,但是UNDO表空间的数据会写入REDO日志中,这样将临时表产生的UNDO数据从UNDO表空间挪到临时表空间,就不会把临时表产生的UNDO信息写入REDO日志中,这样就减少了REDO日志的产生量,也就减少了归档日志的生成量。
ORACLE通过temp_undo_enabled参数来控制临时UNDO段新特性的启用,默认是FALSE关闭状态。
SQL> show parameter undo NAME TYPE VALUE ------------------------------------ ----------- ---------- temp_undo_enabled boolean FALSE undo_management string AUTO undo_retention integer 900 undo_tablespace string UNDOTBS1
下面测试一下在启用和禁用临时UNDO段特性时,产生的REDO信息对比,先创建测试表。
SQL> create global temporary table t_test_temp as select * from T_TEST where 1=2; Table created.
重新打开一个会话,查询当前产生的REDO信息。
SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 4 redo size 1324
在默认情况下也就是禁用临时UNDO段特性的情况下,向一张临时表插入数据。
SQL> insert into t_test_temp select * from t_test; 6136934 rows created.
再次查看这个会话的REDO产生量。
SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 60964 redo size 21357176
可见,在禁用临时UNDO段特性的情况下,向临时表中插入数据会产生很多的REDO数据,这是因为临时表产生的UNDO数据当前保存在UNDO表空间中,而UNDO表空间的数据也会写入到REDO日志。
下面在开一个新会话,并且启用临时UNDO段特性。
SQL> alter session set temp_undo_enabled=true; Session altered.
查看这个会话的当前REDO产生量。
SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 2 redo size 744
然后向临时表中插入同样的数据。
SQL> insert into t_test_temp select * from t_test; 6136934 rows created.
再次查看这个会话的REDO产生量。
SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 3 redo size 1024
可见,在启用临时UNDO段的情况下,对临时表进行插入操作,REDO的产生非常少,这些应该都是数据字典变更产生的REDO。
大家应该知道,COMMIT和ROLLBACK操作是一个事务的终止,COMMIT操作只是打个标记,并不会修改数据,而ROLLBACK操作,是要根据UNDO数据去还原数据的,也就是ROLLBACK操作会修改数据,那么就意味着ROLLBACK操作是会产生REDO和UNDO的,如果是临时表的ROLLBACK操作,因为临时表本身不产生REDO,但是会产生UNDO。
下面分别对上面测试的两个会话进行ROLLBACK操作,再看一下REDO的产生量。
禁用临时UNDO段的情况下回滚后REDO产生量:
SQL> rollback; Rollback complete. SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 121794 redo size 27432588
回滚禁用临时UNDO段的情况下的INSERT操作产生的REDO,基本上等于插入时的REDO产生量。
在看一下启用临时UNDO段的情况下回滚后REDO产生量:
SQL> rollback; Rollback complete. SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 4 redo size 1156
回滚启用临时UNDO段的情况下的INSERT操作产生的REDO,基本上不产生REDO。这是因为临时表的DML操作本身就不生成REDO,而临时表的UNDO数据被保存到的临时表空间,临时表空间的数据也不会写入REDO文件。
本实验只是模拟了INSERT操作,有较真的朋友可以测试下DELETE和UPDATE操作。
最后再吐一下槽,貌似这个功能启用之后,在这个会话中并不能关闭,我的测试数据库版本是12.2.0.1.0版本,下面是测试过程。
[oracle@hm-oradb-01 ~]$ sqlplus dbdream/dbdream@localhost/pdb1 SQL*Plus: Release 12.2.0.1.0 Production on Thu Aug 30 12:27:34 2018 Copyright (c) 1982, 2016, Oracle. All rights reserved. Last Successful login time: Thu Aug 30 2018 10:46:41 +08:00 Connected to: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production SQL> alter session set temp_undo_enabled=true; Session altered. SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 2 redo size 744 SQL> insert into t_test_temp select * from t_test; 6136934 rows created. SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 3 redo size 1024 SQL> insert into t_test_temp select * from t_test; 6136934 rows created. SQL> select name, value from v$mystat natural join v$statname where name in ('redo entries','redo size'); NAME VALUE ---------------------------------------------------------------- ---------- redo entries 5 redo size 1436
在启用临时UNDO段的会话中,禁用临时UNDO段之后,这个禁用操作明显没有生效。