在聊UNDO之前,先来聊下UNDO这个名词。UNDO如果用傻瓜翻译,意思即为不做;当与Oracle数据库联系起来的时候,它也不代表什么都不做,而是意指刚刚发生的那件事儿啊,不做了。所以用另外一个名词来描述它更为准确:撤销。说到撤销这个名词,大家是不是想到了一个快捷键 “ CTRL + Z” ,当我们进行文档、代码、excel等编写工作时,发现写错了、删错了,直接CTRL + Z就恢复到操作之前的内容。UNDO与CTRL + Z在功能上类似,但在属性和结构上比这个快捷键要复杂和强大的多。
下面用比较严谨的语言来描述UNDO即为:
贯穿Oracle数据库始终的一个名词是事务,UNDO数据即为事务行为的一个记录。进一步说UNDO数据是 数据每次更改的前镜像记录,它至少会保留到事务结束。
目录
UNDO数据存在哪
如果提到数据存储,那没什么好说的;UNDO数据存储在UNDO段中,UNDO段存储在UNDO表空间中。对于UNDO数据需要额外多说的是:
- UNDO表空间仅用于UNDO段保存
- 要求在任何给定时间、给定实例中只有一个当前可写的UNDO表空间
- 每一个事务只会分配给一个UNDO段
- 一个UNDO段可以一次处理多个事务
可以用下面的SQL查看undo表空间情况
SELECT * FROM dba_tablespaces;
此外Oracle在建库时,是会默认创建undo表空间的,这也是undo数据默认存储的表空间。在这里顺带提一句,undo表空间是可以自己创建并切换的。但一般情况下,实在是没必要切换。
关于存储这块的更多详细内容,大家如果有需要,可以看下我的另一篇文章:浅谈Oracle存储管理
UNDO的管理
在Oracle9i之前,undo是使用手动管理模式进行管理。Oracle9i之后,undo使用的是自动管理模式。提到这个版本差异的话,现在9i的版本应该已经见不着了吧,所以大家重点了解自动管理就行啦。UNDO的自动管理包括以下内容:
- undo表空间中的数据和空间实现全自动管理
- 表空间自动增加(AUTOEXTEND)
- Oracle的自我调节算法让UNDO表空间获得更好的空间管理特性
以上是Oracle的官方描述,其实翻来覆去说的还是UNDO的表空间管理、段管理。说是自动,也就是说UNDO表空间会进行自动扩展;至于Oracle的自我调节算法,那也不是我们能选择控制的。但对于这个自动管理吧,也是相对来说的;要是真的哪天UNDO表空间满了(毕竟undo数据文件只有一个), 我们也不可能不 “手动” 管管吧🤭。
除了上述的自动空间管理外,我们还可以进行以下管理:
- 配置undo保留时间
- 将UNDO表空间更改为固定大小
- 避免空间的“快照过旧”错误
UNDO的保留时间
undo_retention即为undo保留时间,它指定了已提交的UNDO信息将保留多长时间。我们可以用以下操作来查询undo_retention。
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_retention 设置的是900s(15分钟),这也是Oracle的默认undo保留时间。
或者直接查询动态性能视图v$parameter,可以查看undo的相关参数信息。
SELECT * FROM v$parameter WHERE NAME LIKE '%undo%'
undo_retention 是可以进行手动更改的,修改方法如下。但是不建议随意更改undo_retention,除非你自己知道你自己在做什么,并且清楚操作带来的后果,以及实际的环境资源都掌握,否则别随便动它。
alter system set undo_retention = 1500 scope=both;
前文已经对undo_retention已经有了初步的了解,那么下面我们再深入的探讨下undo_retention的特性。
- 不一定严格按undo_retention执行
undo_retention只是指定了undo数据的过期时间,并不是说undo中的数据一定会在表空间中保留900秒。当undo表空间已被写满,新的事务就会自动覆盖那些已经提交的事务数据,而不会去理会这些数据是否已经过期。
- 超过保留时间的undo数据
undo_retention指定的时间一过,已提交的数据就立刻无法访问,它只是失效,但是只要没有被新数据覆盖就仍然存在,并且可随时被flashback特性引用。如果undo表空间足够大,而数据库又不是那么繁忙,那么undo_retention的值并不会有影响,只要没有事务去覆盖undo数据,就会持续有效。
UNDO的强制保留
这块内容是undo_retention的延申。前文我们提到过,如果undo表空间大小不够了,那么即使未到保留时间(已提交的事务),undo数据也会被覆盖。那么为undo表空间指定retention guarantee的作用是能够确保undo数据在undo_retention指定的保留时间前一定有效。设置retention guarantee ,即使UNDO保留时间会导致事务失败,也会强制执行。
retention guarantee是表空间属性,而不是初始化参数。只能使用SQL命令行。语法如下。
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;
要将保证的undo表空间恢复为正常设置,语法如下。
ALTER TABLESPACE undotbs1 RETENTION NOGUARANTEE;
查看是否开启了retention guarantee
SQL> SELECT tablespace_name, retention FROM dba_tablespaces;
TABLESPACE_NAME RETENTION
------------------------------ -----------
SYSTEM NOT APPLY
SYSAUX NOT APPLY
UNDOTBS1 NOGUARANTEE
TEMP NOT APPLY
USERS NOT APPLY
在这里需要和大家一起总结一下:
1、如果不设置retention guarantee,那么当前Oracle数据库是优先保障事务正常;
2、如果设置了retention guarantee,那么当前Oracle数据库优先保障的是undo数据;
UNDO能干嘛用
在本篇文章开头我们说了undo可以像CTRL + Z一样撤销操作;但undo的用途远不止于此。下面对此进行简单梳理总结。
- 回滚操作
回滚操作这个应该是Oracle使用者最常用的一个操作之一了吧;无论是在平时测试SQL时还是在写PLSQL存储过程时都会经常使用到。当您删除或更新某个数据时,执行完操作;突然发现卧槽忘记加条件了、卧槽加错条件了、卧槽搞错表了等等时刻,只需要点击数据库连接工具上的回滚按钮或者执行一下rollback,就可以将之前的误操作给撤销。数据修改前的数据,就是保存在undo中的数据哦😄。
- 读取一致性查询
读取一致性这个事儿呢,就和数据库并发扯上关系了,如果大家有需要,可以看下我的另一篇文章Oracle数据库并发。
- 闪回操作
说到闪回操作呢,我对它的理解一直都是回滚操作的升级版、promax版、plus版。回滚操作是对刚刚发生的事务进行回滚。而闪回操作,是可以对指定的表,定位到具体事务发生之前的某个时间点进行前镜像数据恢复(只要undo表空间中还保留着该表的前镜像数据)。