暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle Undo回滚段管理

oracleEDU 2017-08-20
1242

什么是Undo

undo就是原来数据的一份拷贝,用来对事务数据的恢复。

Undo的作用
  1. 事务回滚

  2. 读一致性、闪回查询

  3. 失败事务的恢复

undo data还原数据:

执行DML(insert update delete ,merge)语句的时候就会产生还原数据。副本至少要保存到事务结束,事务结束了,就看用户定义的保留策略。还原事务就是支持事务处理的,保证回滚一定成功。

回滚数据只能存在回滚段

回滚段是在磁盘上的一段空间,当一个事务开始的时候,会首先把变化前的数据和变化后的数据写入日志缓冲区,然后把变化的数据写入回滚段,最后才在数据缓冲区中修改数据(要注意这个过程中只有写回滚段才是必须真正的立即写磁盘,日志缓冲区内容在满足一定的条件后可能被写入磁盘,但在事务提交的时候日志必须写入磁盘,而数据缓冲区中的数据依赖于检查点和dbwr进程的活动才写回磁盘。

例:

update scott.emp set sal=0 where sal=3000;

首先把该语句的整个操作包括数据0 ,3000写入日志缓冲区,然后把数据3000写入回滚段,最后把0修改到数据缓冲区,当发出commit命令时,如果日志缓冲区内容还没有写入到日志文件,必须写进日志文件,回滚段把该事务标记为已经提交,数据缓冲区中块的这些事务也标记为已提交(注意:在大事务的情况下如果数据缓冲区中块已经被写入磁盘或者该事务更改超过了数据缓冲区大小10%则不在对这些块标记该事务为已经提交,这会影响到下次读取该快)。当如果回退事务,则数据库将把回滚段中数据3000读取出来写回数据缓冲区,回滚的变化的过程写入日志,如果事务很大,数据缓冲区数据已经被写入磁盘了,回退代价极其昂贵的操作,所以系统中的事务回滚率要比较低,否则系统或者程序设计有问题。

查询回滚率

SQL> select name,value from v$sysstat where name in ('user commits','transaction rollbacks');

NAME      VALUE

---------------------------------------------------------------- ----------

user commits      14490

transaction rollbacks 249

减少Undo量

事务由一组DML语句组合,要么都成功,要么都失败。

DML:insert,update,delete,merge

回滚段存储内容:

对insert操作,回滚只需要记录插入记录的ROWID(行的物理地址,隐含的值),如果回退,只需要将该记录根据rowid删除。

select rowid, empno,ename,sal from scott.emp

SQL>

ROWID EMPNO ENAME SAL

------------------ ---------- ---------- ----------

AAAR3xAAEAAAACTAAH 7369 SMITH 880

AAAR3xAAEAAAACTAAO 7499 ALLEN       1760

AAAR3xAAEAAAACTAAP 7521 WARD       1375

AAAR3xAAEAAAACTAAQ 7566 JONES        3272

SQL> select ename ,sal from scott.emp where rowid='AAAR3xAAEAAAACTAAH';

ENAME             SAL

----------     ----------

SMITH               880

Tips:通过rowid删除最快,insert undo 存的是rowid,insert 产生最少undo 其次update  ,delete 产生undo最多。通常进行大规模删除时,推荐通过分批删除分次提交,减少对与回滚段的占用。

对与update操作,回滚段只需要记录被更新字段的旧值(前镜像),回退时通过旧值覆盖新值即可完成回滚。

对与delete 操作,oracle必须记录整行数据,在回滚时,oracle通过一个反向操作恢复删除的数据。

undo中的数据至少要保留到整个事务结束,事物结束后的undo空间是可以被重用的。

Undo的操作练习

创建一个undo表空间

SQL> create undo tablespace undo01 datafile '+data' size 5m autoextend off;

Tablespace created.

查看当前undo表空间

SQL> show parameter undo

NAME     TYPE VALUE

------------------------------------ ----------- ------------------------------

undo_management     string AUTO

undo_retention     integer 900

undo_tablespace     string UNDOTBS1

设置当前undo表空间为刚创建的undo01

SQL> alter system set undo_tablespace=undo01;

System altered.

再次查看

SQL> show parameter undo

NAME     TYPE VALUE

------------------------------------ ----------- ------------------------------

undo_management     string AUTO

undo_retention     integer 900

undo_tablespace     string UNDO01        #当前产生Undo信息

创建一个大表

SQL> conn scott/oracle

SQL> create table bigundotest as select * from all_objects;

Table created.

SQL> insert into bigundotest select * from bigundotest;

71111 rows created.

SQL> commit;

SQL> select count(*) from scott.bigundotest;

  COUNT(*)

----------

    142222

查看这个表的大小

SQL> select sum(bytes)/1024/1024 from dba_extents where owner='SCOTT' and segment_name='BIGUNDOTEST';

SUM(BYTES)/1024/1024

--------------------

 17

这个表有17M,实际设置undo空间5M且不允许自动扩展,是容不下的。

删除这个表

SQL> delete from bigundotest;(这个事务不能被执行,在执行前先去找有没有足够的undo空间,如果没有,该事务就不会执行)

delete from bigundotest

            *

ERROR at line 1:

ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDO01'

解决

方法1:truncate

方法2:分次删除

方法3:增加undo空间

1. truncate

SQL> truncate table bigundotest;

Table truncated.

SQL> select count(*) from bigundotest;

  COUNT(*)

----------

0

2. 在不增加undo空间的情况下用delete删除bigundotest表的数据

SQL> delete from bigundotest where rownum <=10000;

10000 rows deleted.

SQL> commit;

Commit complete.

SQL> delete from bigundotest where rownum <=10000;

10000 rows deleted.

SQL> commit;

……

分次删除。

3. 增加undo空间

允许自动增长,则delete后的数据进入undo,undo被撑大

开启undo01自动增长

SQL> select file_id from dba_data_files where tablespace_name = 'UNDO01';

   FILE_ID

----------

7

SQL> alter database datafile 7 autoextend on next 1M maxsize 1G;

Database altered.

事务提交,扩展的undo不会被自动回收回去。

Undo段和事务的关系

事务开始的时候,系统自动分配一个undo segment给该事务使用,一个事务只能使用唯一一个段。

一个undo segment可以被多个事务,段式轮询 ,重复使用。

系统默认分配了多少个段

SQL> select * from v$rollname;

       USN NAME

---------- ------------------------------

0 SYSTEM

11 _SYSSMU11_1690522839$

12 _SYSSMU12_3701313965$

13 _SYSSMU13_2388787087$

14 _SYSSMU14_3894246580$

15 _SYSSMU15_2611523263$

16 _SYSSMU16_4183000398$

17 _SYSSMU17_3094306745$

18 _SYSSMU18_4045319073$

19 _SYSSMU19_2411379205$

20 _SYSSMU20_1246251057$

11 rows selected.

10个段服务很多事务,可能前面事务的undo段被后面的事务覆盖,没有提交的事务的undo一定保存,提交事务不一定保留。

事务是否被分配了undo segment

查 v$transaction

查看哪个用户在使用哪个回滚段

SELECT s.username, u.name 

        FROM v$transaction t, v$rollstat r, v$rollname u, v$session s 

        WHERE s.taddr = t.addr 

        AND t.xidusn = r.usn 

        AND r.usn = u.usn 

        ORDER BY s.username;

再开启一个session 用户产生事务

SQL> insert into test values(1,2);

1 row created.

事务不提交

再次执行

SELECT s.username, u.name 

        FROM v$transaction t, v$rollstat r, v$rollname u, v$session s 

        WHERE s.taddr = t.addr 

        AND t.xidusn = r.usn 

        AND r.usn = u.usn 

        ORDER BY s.username; 

USERNAME                       NAME

------------------------------ ------------------------------

SCOTT       _SYSSMU16_4183000398$

用户事务结束 --> rollback commit  --> 回滚段释放

通过事务名找出段

SQL> set transaction name 'update test c1';

Transaction set.

SQL> update scott.test set c1=0;

1 row updated.

select xid, status,start_time,xidusn seg_num, r.name seg_name

 from v$transaction t join v$rollname r

 on t.xidusn=r.usn

 where t.name='update test c1';

XID STATUS  START_TIME  SEG_NUM

---------------- ---------------- -------------------- ----------

SEG_NAME

------------------------------

0C00130008000000 ACTIVE  08/03/17 09:43:20       12

_SYSSMU12_3701313965$

如果事前没有给事务取名字,怎样查到使用的是哪个回滚段

查看当前事务使用的回滚段

SQL> select a.usn,a.xacts,b.name from v$rollstat a,v$rollname b where a.usn=b.usn and a.xacts >0 ;

       USN XACTS NAME

---------- ---------- ------------------------------

12    1 _SYSSMU12_3701313965$

或者

1. 先查出事务ID,再通过事务ID查

    查看当前会话的session ID:

    SQL> select sid from v$mystat where rownum=1;

       SID

----------

63

SQL> select userenv('sid') from dual;    #这种方法只能在Oracle10g以后用

USERENV('SID')

--------------

   63

2. 根据会话号查出事务IDSQL> select xid from v$transaction where addr in (select taddr from v$session where sid=&sid);

Enter value for sid: 63

XID

----------------

0C00130008000000

3. 根据事务ID查出该事务使用的回滚段

select xid,status,start_time,xidusn seg_num, r.name seg_name

 from v$transaction t join v$rollname r

 on t.xidusn=r.usn

 where xid=  '0C00130008000000';

XID STATUS  START_TIME  SEG_NUM

---------------- ---------------- -------------------- ----------

SEG_NAME

------------------------------

0C00130008000000 ACTIVE  08/03/17 09:43:20       12

_SYSSMU12_3701313965$

查询V$ROLLNAME、V$ROLLSTAT和V$TRANSACTION视图可以提供用户如何使用回滚段和撤消表空间的信息。

通常情况下,在一个时间点上不应让多个用户访问同一个回滚段(尽管这是被允许的)。

select a.name, b.extents, b.rssize, b.xacts,b.waits, b.gets, optsize, status 

from v$rollname a, v$rollstat b 

where a.usn = b.usn;

Undo表空间的自动管理

SQL> show parameter undo

NAME     TYPE VALUE

------------------------------------ ----------- ------------------------------

undo_management     string AUTO

undo表空间不需要人工管理。

DBA有两个工作:

  1. 根据闪回策略设置undo保留时间和空间大小

  2. 避免“snapshot too old” errors

设置保留时间

SQL> show parameter undo

NAME     TYPE VALUE

------------------------------------ ----------- ------------------------------

undo_management     string AUTO

undo_retention      integer 900    #设置的900秒

undo_tablespace     string UNDO01

指定那些已经提交的事务的undo信息保留多久(前提undo空间够大,不够大的时候,会飞重用),没有提交的事务一定保留,提交了就由undo_retention 控制保留多久,但是前提:你的undo足够大,如果undo空间不够,不等待900秒就会被覆盖。

alter system set undo_tablespace=undotbs1;

什么时候设置undo_retention

  1. undo tablespace设置为自动增长,如果没有启动自动增长,则忽略该参数

  2. undo tablespace里存储了大对象数据

  3. 如果想启用这个选项guarantee retention,你想确定你的undo data的保留时间(无论空间是否足够,都不可以删除指定的undo data)

例:

要求至少可以闪回1天内的数据

步骤:

  1. 设置保留时间

  2. alter system set undo_retention=86400;

  3. 开启强制保留

        alter tablespace "UNDO01" retention guarantee;

检查:

SQL> select  TABLESPACE_NAME,CONTENTS,RETENTION

    from dba_tablespaces

    where CONTENTS='UNDO';

TABLESPACE_NAME                CONTENTS  RETENTION

------------------------------ --------- -----------

UNDOTBS1                       UNDO      NOGUARANTEE

UNDO01                            UNDO      GUARANTEE

开启后一定监视undo表空间大小,如果空间不够新事务,则新事务无法执行。

取消guarantee

ALTER TABLESPACE "UNDO01" RETENTION NOGUARANTEE;

估算undo空间大小

估算undo空间大小

方法1:

EM中指导器  home --> 最下面advisor center --> Automatic Undo Management

方法2:

SQL语句估算

查看udno的信息 (保留时间间隔 每分钟产生的undo信息量等)

ELECT end_time,begin_time,undoblks

FROM   v$undostat;

END_TIME  BEGIN_TIM   UNDOBLKS

--------- --------- ----------

29-JUL-13 29-JUL-13         14

29-JUL-13 29-JUL-13         32

29-JUL-13 29-JUL-13         41

29-JUL-13 29-JUL-13        146

29-JUL-13 29-JUL-13       1836

29-JUL-13 29-JUL-13         51

29-JUL-13 29-JUL-13         13

29-JUL-13 29-JUL-13         42

29-JUL-13 29-JUL-13         32

29-JUL-13 29-JUL-13        160

29-JUL-13 29-JUL-13         35

END_TIME  BEGIN_TIM   UNDOBLKS

--------- --------- ----------

29-JUL-13 29-JUL-13         43

29-JUL-13 29-JUL-13         41

29-JUL-13 29-JUL-13         48

29-JUL-13 29-JUL-13        156

建议:先运行一段时间的自动扩展,稳定后取消。


参考文档:

Administrator's Guide --> Managing Undo


最后修改时间:2021-04-28 19:52:34
文章转载自oracleEDU,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论