Oracle的Undo机制是啥

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle的Undo机制是啥相关的知识,希望对你有一定的参考价值。

1. UNDO表空间用于存放UNDO数据。当执行DML操作时,Oracle会将这些操作的旧数据写入UNDO段。管理UNDO数据不仅可以使用回滚段,还可以使用UNDO表空间。
  2. UNDO数据的作用:当用户执行DML操作修改数据时,UNDO数据被存放在UNDO段,而新数据则被存放到数据段中,如果事务操作存在问题,就需要回退事务,以取消事物变化。
  例如:执行完UPDATE emp SET sal=1000 WHERE empno=7788后,发现应该修改雇员7963的工资,而不是7788.此时应该执行ROLLBACK语句。
  3.读一致性
  用户检索数据时,ORACLE总是使用户只能看到被提交过的数据,这是由Oracle自动提供的。当用户修改数据,但是没有提交时,另外一个用户使用select语句查找该值时,该值就是从undo表空间中取得的。
  4.事务恢复
  事务恢复是例程恢复的一部分,它是由Oracle Server自动完成的。如果在数据库运行过程中出线历程失败,那么当启动Oracle Server时,后台进程SMON会自动执行例程恢复。执行例程恢复时,Oracle会重做所有未应用的记录。然后打开数据库,回退未提交事务。
  5.倒叙查询
  倒叙查询用于取得某一特定时间点的数据库数据。
  6.UNDO_MANAGEMENT
  使用初始化参数用于指定UNDO数据的管理方式。如果使用自动管理模式,必须设置该参数为AUTO,此时采用UNDO表空间管理UNDO数据;如果使用手工管理模式,必须设置该值为MANUAl,此时采用回滚段管理UNDO数据。
  7.UNDO_TABLESPACE
  用于指定例程所要使用的UNDO表空间。使用自动UNDO管理模式时,通过配置该参数可以指定例程所要使用的UNDO表空间。
  使用RAC结构时,必须为每个例程配置一个独立的UNDO表空间。
  8.UNDO_RETENTION
  该参数用于控制UNDO数据的最大保留时间,其默认值为900秒,该值时倒叙查询可以查看到的最早时间点。
  9.UNDO表空间上不能建立任何数据对象。
参考技术A Oracle绝对禁止一个用户查看另一个用户未提交的事务数据。
启动一个DML事务时,已修改数据的象前版本被缓存在database buffer cache,再有一个缓冲副本被写入一个回退段(undo segment)上。
参考技术B undo 机制的目的就是事务的一致性,修改的数据,即前镜像保存在undo 块中,记录的日志写在redo块中,这样旧的数据和新的数据都有了记录

oracle学习笔记 undo段及区的状态和使用

oracle学习笔记 undo段及区的状态和使用


 

先简单的看一下undo的作用,以及oracle是怎么使用undo的
这次讲课一步一步的去渗入,一步步去深入



 

一)undo的作用


看一下undo的作用


undo的作用从某种意义上来讲
简单的用比较概括的话说一下


undo表空间里面有很多段


先不看平时oracle做select的时候
oracle开始一个事务的时候会用到undo表空间


比如说一个事务比如我做一个delete
oracle执行delete语句
要删除一行
oracle这时候会把删除前的这一行
会把修改前的数据要修改的一行放到undo表空间的undo段里面去


oracle去选择用哪个段的过程是自动的


oracle开始一个事务以后
这个事务会对数据进行修改
oracle就把修改前的数据
放到undo表空间里面的undo段里面去


所以说undo表空间的第一个作用
其实undo表空间一直在做这么一件事情一件最简单的事情
将修改前的数据保存在undo表空间里面


将修改前的数据保存在undo表空间里的undo段里面


所以说如果一个事务修改的数据块修改的数据越多
它用的undo表空间里面undo段的空间越多
我们讲过undo段可以自动的自由的伸缩


这是undo表空间最简单的作用最简单的一个工作



 

二)使用undo的原因


当然在这个工作基础上
为什么在undo表空间里面要把oracle一个进程修改前的数据放到undo表空间里面去呢?


1)回滚


第一个意义,事务可以回滚


所谓的回滚
我开始一个事务,对事务进行修改,修改到某个阶段以后
突然我发现,修改是错了,我想把所有的修改给它恢复回去


我这个oracle事务修改了十个数据块
修改完了以后突然发现不对修改错了
可以回滚回去,将这十个数据块的修改,恢复到以前的状态
这叫rollback叫回滚


同时还有另外一个情况
一个事务还没有完成,这个事务相关的会话死掉了
这个事务也需要回滚,需要自动回滚


前面是手工回滚的,后面这个需要自动回滚
也就是oracle的事务有的时候需要回滚
不管自动的手动的都需要回滚


那么这个事务需要回滚
所谓的回滚就是把这个事务修改前的事务拷贝回来
就需要修改前的数据
修改前的数据在undo表空间里面


undo表空间第一个作用最突出的作用是回滚
因为事务可以提交可以回滚,所以事务才能保证一致性


如果只能提交
那么一个数据修改了十行
修改到第十行的时候,突然发现第二行坏了,第二行修改错了
如果不能回滚的话数据可能不一致


所以事务能提交能回滚是事务保持一致性的一个要求
oracle事务的回滚靠undo表空间


所以undo表空间里面的第一个作用是:可以回滚


2)提供读一致性


第二个作用


oracle有一个特点
一个会话的未提交事务相对另一个会话是看不见的


A会话上来把一个数据1改成2
B会话要来读
A会话没有提交的时候
B会话上来读这个数据的时候,读到的是1不是2


也就是说oracle保证我读的数据一定是提交后的数据


oracle避免一个会话读到另一个会话的未提交数据
以前讲过用默认隔离机制实现
一个会话上来读到的数据都是已提交数据


这里要靠undo表空间


比如A会话上来以后把1改成2了,但是没有提交
B会话上来读同样的数据的时候
数据实实在在的已经被改成2了


这时候B会话只读已提交的数据
但2没有提交


既然要读的数据没有提交
oracle就读这个没有提交的上面的事务的数据
就是1
1在undo里面


第二提供读一致性


B会话上来读的时候,读这个数据的时候
一看这个数据被修改了,而且事务没有提交
B会话就会额外的申请一个块,在buffercache里面申请一个数据块


申请一个数据块以后
把它要读的数据,对应的undo段里面的数据写过来
也就是把1写到在buffercache里的新申请的那个数据块里面
然后读buffercache的这个数据块
这个块就是CR(consistent read)块


B通过构造CR块达到了一致性读的目的
关于整个的过程,里面有很多详细的细节


大家只要知道
undo表空间的第二个作用是:提供读一致性
保证oracle读的数据永远是已提交数据,未提交数据不会读的


3)实例崩溃恢复


undo的第三个作用,就是实例崩溃恢复


实例崩溃以后恢复过程分两步


第一步前滚
前滚尽量多的把所有的脏块构造出来


还要回滚
因为前滚出了很多的脏块
有可能是一些未提交事务所造成的脏块
这些脏块所对应的事务需要回滚
既然需要回滚的话就要用到undo表空间


所以记住undo表空间有三个作用


第一个:回滚
第二个:提供读一致性
第三个:实例崩溃恢复,实例崩溃恢复里面的回滚


undo表空间简单的实现了保存修改前的数据
在这个基础上它能实现三个功能
读一致性、回滚和实例崩溃恢复



 

三)undo段中区的状态


undo段中区的状态很有意思

free、expired、inactive还有active


1)段情况


检查UNDO Segment状态
select usn,xacts,rssize/1024/1024/1024,hwmsize/1024/1024/1024,shrinks
from v$rollstat order by rssize;

查询结果


SQL> select usn,xacts,rssize/1024/1024/1024,hwmsize/1024/1024/1024,shrinks from v$rollstat order by rssize;

       USN      XACTS RSSIZE/1024/1024/1024 HWMSIZE/1024/1024/1024    SHRINKS
---------- ---------- --------------------- ---------------------- ----------
         9          0            .000114441             .001091003          1
         4          0            .000175476             .000968933          4
         3          0            .000175476             .000846863          4
        10          0            .000297546             .003044128          2
         0          0            .000358582             .000358582          0
         8          0            .001091003             .004020691          3
         7          0            .001091003             .002067566          1
         6          0            .001091003             .002067566          1
         2          0            .001091003             .002067566          1
         1          0            .001091003             .001091003          0
         5          0            .001091003             .002067566          1

11 rows selected.


我们看现在undo段有十一个段

USN列为段的编号,有0号1号等



通过下面的语句也可以看到


SQL> select * from v$rollname;

       USN NAME
---------- ------------------------------
         0 SYSTEM
         1 _SYSSMU1$
         2 _SYSSMU2$
         3 _SYSSMU3$
         4 _SYSSMU4$
         5 _SYSSMU5$
         6 _SYSSMU6$
         7 _SYSSMU7$
         8 _SYSSMU8$
         9 _SYSSMU9$
        10 _SYSSMU10$

11 rows selected.


段是有编号的


而从v$rollstat查出的是每个段的使用情况


我们来看段中区的状态


undo表空间一开始是默认建了一堆段
这里面还有很多空闲空间,建了十个段


比如undo表空间10G
它建了十个段,不是每个段一个G
一开始段最小化,段是最小的只分配了一个区

一开始一个段只分配了一个或者几个区


2)区的free状态


在undo表空间里面有一些空间
有的空间没有用就是free的
就是这个区没有分配给这里面的任何一个段
这个区的状态就是free的


3)区的active状态


一个事务开始了
开始以后事务就会找到其中一个undo段


假设它选择了使用了其中的一个段
然后这个事务进行了大量的操作


这个段比如开始有一个区
这个区用完了以后
这个事务还没有结束,要分配别的区
又分配了一个区还不够又分配了一个区
这个过程是自动操作的


这个事务使用一个段
一共使用这个段的四个区
事务还没有提交,一直没有提交


也就是这个段的四个区
被这个事务所使用,这个事务没有提交
这时候这四个区的状态就是active


区是active就表示这个区中的事务还没有提交


3)区的inactive状态
这个事务过一会儿提交了
提交了以后,这四个区的状态就是inactive


4)从inactive状态到expired状态


还有一个


这个事务占用了四个区,占用了四个区以后,然后这个事务提交了
提交了以后,按正规来讲
这四个区里面对应的事务既然已经提交了,这时候这四个区就可以被重用了
就可以再次被使用了,也就是说可以被覆盖了


默认隔离级别,既然已经提交了,就不能回滚了
不能回滚了,我们还要这个undo数据就没有什么意义了
无论是读一致性还是崩溃恢复还是回滚都没有意义了


这时候按正规来讲inactive数据就可以被覆盖了


但是有时oracle会希望
已经提交的事务所对应的回滚表空间中回滚段中的区尽量的再保持一段时间
也就是说,oracle希望inactive状态的这些区再保存一段时间


有一个undo_retention参数


SQL> Show parameter undo

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_management                      string      AUTO
undo_retention                       integer     900
undo_tablespace                      string      UNDOTBS1


就是NAME为undo_retention的参数
这里时间900秒,900秒就是15分钟


这里通过undo_retention
对inactive状态的这些区会保留十五分钟
15分钟以后这个区的状态就变成expired状态,expired是过期的意思


expired过期以后我们就可以覆盖了


5)undo的inactive状态的区的保持原因


在oracle的默认隔离级别read committed下
保持数据的读一致性只需要回滚未提交事务来构造CR块
这时用到active状态的undo区


但在隔离级别serializable下的读一致性
有时也要通过回滚已提交事务得到数据
这时要用到inactive状态的undo区
因为默认inactive的区是可以被覆盖的
如果被覆盖了,则无法再进行回滚
就会报ORA-01555:snapshot too old错误
就是需要建立的快照时间太旧,当前系统没有这么老的数据。
这种情况的需求,就需要尽量的保留需要的inactive状态的undo区
可以延长undo_retention时间和进一步保证此时间
使inactive状态的区能够更长时间的被使用


除了事务使用inactive状态的undo区外
长时间的保留这个状态的区,主要还是因为一个oracle9i出现的新技术Flashback
有几种子命令,大致分为两类:查询和恢复
通过闪回查询可以得到某个表在其某个SCN时的状态,
并且可以通过闪回可以使数据恢复到某个SCN点


其实闪回技术对查询某时间点的老数据是很有效的
但如果使用这些数据来恢复库,
如恢复一个表到一个老的时间点,要保证数据正确有很大的难度
因为一个库中各个表是有关联关系的
如果一个表的数据某个时间进行了修改,库再使用这些数据又进行了其它表的修改
这样只把第一个表闪回,其它表的数据就无法保证一致性了
所以闪回数据要保证数据正确,只能闪回最后一个完成的事务
闪回技术也提供了闪回整个数据库的命令,
这样结果整个库数据在恢复到的时间点上是一致了,
但也丢失了此时间点后的很多已提交事务,仍然是不能接受的


所以这个技术对单独的闪回查询有可用性,对于恢复数据可行性作用不大!


事务数据的正确不要寄希望于任何的恢复技术,应在数据写入时进行保障。
因为大量的数据彼此相关联,个别已经写入的数据是不好改动的。


在oracle11G甚至又引入了Flashback Data Archive(闪回数据归档)技术,
闪回归档使用指定表空间进行undo数据的归档
并且通过设置归档的retention,可以保留更长的时间,保留三年五年都可以
这么长的时间代价是磁盘空间的大量消耗
undo信息从内存写到磁盘也会损失一部分的程序性能



 

四)各状态的覆盖情况


active表示这个区中有活动的事务,active的区不能被覆盖


inactive表示这个区中的事务已经提交
但是这个区还没有过undo_retention的时间,也就是没有过900秒
它这时是inactive


原则上是oracle尽量的不覆盖inactive
但是如果undo表空间空间压力比较大的时候,oracle也会去覆盖这个inactive
inactive状态oracle尽量的在undo_retention这个时间内不覆盖
但也有可能被覆盖


inactive的区一旦过了undo_retention时间后就会变成expired
expired时间长了以后,oracle也会自动释放
原则上expired一般不会释放成free
expired到底多长时间释放成free老师也没有测过
但根据以前的使用情况一般的不释放成free


这是段中区的几个状态


free就是从来没用过的
expired是过了undo_retention时间的
inactive是提交的
active是未提交的



 

五)区的状态查询



有sql语句可以查一下这些区的状态


显示UNDO区信息语句
 SELECT extent_id, bytes, status FROM dba_undo_extents
 WHERE segment_name='_SYSSMU1$';


_SYSSMU1$这个段我们此前查的有三个区


SQL> SELECT extent_id, bytes, status FROM dba_undo_extents WHERE segment_name='_SYSSMU1$';

 EXTENT_ID      BYTES STATUS
---------- ---------- ---------
         0      65536 EXPIRED
         1      65536 EXPIRED
         2    1048576 EXPIRED


我们发现这个段的三个区都是EXPIRED,都过期了


这就是undo段中区的状态

检查UNDO Segment状态可以使用语句:
select usn,xacts,rssize/1024/1024/1024,hwmsize/1024/1024/1024,shrinks from v$rollstat order by rssize;



 

六)undo_retention保持的保证


有种情况我想严格要求
我的undo表空间里面undo段里面的inactive区在undo_retention的时间里面不要被覆盖


比如undo_retention时间900秒
我希望inactive的区至少保留900秒以后再被覆盖


这个时候我们可以将表空间的状态改成guarantee(保证)


这个操作很简单


SQL> alter tablespace undotbs1 retention guarantee;

Tablespace altered.


改成guarantee以后
Tablespace altered提示执行完了


以后undo表空间里面的所有的inactive的区
一直会被保留,保留到expired以后才被覆盖


如果你想改回来,使用noguarantee


SQL> alter tablespace undotbs1 retention noguarantee;

Tablespace altered.


改完以后查guarantee状态,管理员表dba_tablespaces有此信息


SQL> desc dba_tablespaces;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TABLESPACE_NAME                           NOT NULL VARCHAR2(30)
 BLOCK_SIZE                                NOT NULL NUMBER
 INITIAL_EXTENT                                     NUMBER
 NEXT_EXTENT                                        NUMBER
 MIN_EXTENTS                               NOT NULL NUMBER
 MAX_EXTENTS                                        NUMBER
 PCT_INCREASE                                       NUMBER
 MIN_EXTLEN                                         NUMBER
 STATUS                                             VARCHAR2(9)
 CONTENTS                                           VARCHAR2(9)
 LOGGING                                            VARCHAR2(9)
 FORCE_LOGGING                                      VARCHAR2(3)
 EXTENT_MANAGEMENT                                  VARCHAR2(10)
 ALLOCATION_TYPE                                    VARCHAR2(9)
 PLUGGED_IN                                         VARCHAR2(3)
 SEGMENT_SPACE_MANAGEMENT                           VARCHAR2(6)
 DEF_TAB_COMPRESSION                                VARCHAR2(8)
 RETENTION                                          VARCHAR2(11)
 BIGFILE                                            VARCHAR2(3)


有个RETENTION字段


可以这样查


SQL> select TABLESPACE_NAME,RETENTION from dba_tablespaces;

TABLESPACE_NAME                RETENTION
------------------------------ -----------
SYSTEM                         NOT APPLY
UNDOTBS1                       NOGUARANTEE
SYSAUX                         NOT APPLY
TEMP                           NOT APPLY
USERS                          NOT APPLY
EXAMPLE                        NOT APPLY

6 rows selected.


这里所有表空间都查了
其实只想找undo表空间UNDOTBS1的信息
提示NOGUARANTEE


因为别的表空间里面无所谓GUARANTEE还是NOGUARANTEE
它们的结果是NOT APPLY


试着改变一下users表空间的retention


SQL> alter tablespace USERS retention guarantee;
alter tablespace USERS retention guarantee
*
ERROR at line 1:
ORA-30044: 'Retention' can only specified for undo tablespace


结果提示retention只对undo表空间有效


再把undo表空间改成guarantee


SQL> alter tablespace undotbs1 retention guarantee;

Tablespace altered.


改完以后再去查一下


SQL> select TABLESPACE_NAME,RETENTION from dba_tablespaces;

TABLESPACE_NAME                RETENTION
------------------------------ -----------
SYSTEM                         NOT APPLY
UNDOTBS1                       GUARANTEE
SYSAUX                         NOT APPLY
TEMP                           NOT APPLY
USERS                          NOT APPLY
EXAMPLE                        NOT APPLY

6 rows selected.


看一下是GUARANTEE


undo_retention时间show parameter可以看




七)undo段空间选择区扩展的方式


我们简单的看一下oracle中段区块的释放情况
oracle中undo表空间undo段使用情况


一开始数据库建立随之建立了一堆的undo段


首先一个事务开始的时候它占用一个undo段就使用undo段
随着事务的修改
undo段里面这一个区已经不够了
这时候oracle在undo表空间里面优先找free的区去补上去分配上


如果free的区没有了
我们知道undo表空间里面的数据文件可以自动的扩
第二步没有free它会自动的想办法去扩undo表空间
扩出空间来就有free了


如果free用完了扩表空间又扩不了了
再去优先使用expired的区扩undo段


expired也没有了就用inactive


如果这个表空间被guarantee了inactive不能用
这时候空间就不够用了
空间不够就没办法了
这个事务就挂起了,时间长了就会死掉,就失败了


这就是undo表空间的使用情况
后面会讲我们如何去判断undo表空间该设多大



这里要知道


先用free,然后再扩空间,再expired,实在不行的话再inactive


这是undo表空间里面段区块以及一个具体的使用情况



2017年6月28日
  文字:韵筝

以上是关于Oracle的Undo机制是啥的主要内容,如果未能解决你的问题,请参考以下文章

Oracle学习笔记 读一致性(ORA-01555错误机制分析)及Undo表空间大小设置

Oracle 事务和 UNDO 的内部管理机制是怎样的?

Oracle学习笔记 Oracle IMU及Redo Private Strands技术

oracle学习笔记 undo表空间概述

oracle体系-10-undo

ORACLE中,数据库的redo与undo分别是啥呀,两者是啥关系呢?