ITPub博客

首页 > Linux操作系统 > Linux操作系统 > Oracle Undo Redo通俗理解

Oracle Undo Redo通俗理解

原创 Linux操作系统 作者:xz43 时间:2011-01-28 10:15:17 0 删除 编辑

什么是REDO

REDO记录transaction logs,分为online和archived。以恢复为目的。

比如,机器停电,那么在重启之后需要online redo logs去恢复系统到失败点。

比如,磁盘坏了,需要用archived redo logs和online redo logs去恢复数据。

比如,truncate一个表或其他的操作,想恢复到之前的状态,同样也需要。

什么是UNDO

REDO 是为了重新实现你的操作,而UNDO相反,是为了撤销你做的操作。

比如,你的一个TRANSACTION执行失败了或你自己后悔了,则需要用 ROLLBACK命令回退到操作之前。

回滚是在逻辑层面实现而不是物理层面,因为在一个多用户系统中,数据结构,blocks等都在时时变化,比如我们 INSERT一个数据,表的空间不够,扩展了一个新的EXTENT,我们的数据保存在这新的EXTENT里,其它用户随后也在这EXTENT里插入了数据,而此时我想ROLLBACK,那么显然物理上讲这EXTENT撤销是不可能的,因为这么做会影响其他用户的操作。所以,ROLLBACK是逻辑上回滚,比如对INSERT来说,那么ROLLBACK就是DELETE了。

COMMIT

    以前,常想当然的认为,一个大的TRANSACTION(比如大批量地INSERT数据)的COMMIT会花费时间比短的TRANSACTION长。而事实上是没有什么区别的,因为ORACLE在COMMIT之前已经把该写的东西写到DISK中了,我们COMMIT只是:

1,产生一个SCN给TRANSACTION,SCN简单理解就是给TRANSACTION排队,以便恢复和保持一致性。

2,写REDO到DISK中(LGWR,这就是log file sync),记录SCN在ONLINE REDO LOG,当这一步发生时,我们可以说事实上已经提交了,这个TRANSACTION已经结束(在V$TRANSACTION里消失了)。

3,SESSION所拥有的LOCK(V$LOCK)被释放。

4,Block Cleanout(这个问题是产生ORA-01555: snapshot too old的根本原因)。

ROLLBACK

    ROLLBACK和COMMIT正好相反,ROLLBACK的时间和TRANSACTION的大小有直接关系。因为ROLLBACK必须物理上恢复数据。COMMIT之所以快,是因为ORACLE在COMMIT之前已经做了很多工作(产生UNDO,修改BLOCK,REDO,LATCH分配),ROLLBACK慢也是基于相同的原因。

ROLLBACK会
       1,恢复数据,DELETE的就重新INSERT,INSERT的就重新DELETE,UPDATE的就再UPDATE。
       2,RELEASE LOCK 。
  
       ROLLBACK要比COMMIT消耗更多资源,因为ORACLE认为你一旦做数据更新,那么就意味着你要COMMIT(其他数据库不全是这种设计理念,比如DB2),所以在你更新数据的时候就做了大量的工作,这也可以理解为什么不建议用TABLE来做TEMPORARY TABLE。(TEMP TABLE消耗的REDO比固定表在INSERT时要少很多,UPDATE时差不多是1/2,但是DELETE却相差无几)。

REDO

       产生REDO 越多,你的系统越慢,不但影响你自己的SESSION,还影响其他SESSION,LGWR管理REDO,并且是TRANSACTION的结束标志。

       首先要知道怎么监控REDO,当然,SET AUTOTRACE ON可以,不过只能监控DML语句,而像PROCEDURE则无法监视。那么我们就需要观察字典了,V$MYSTAT, V$STATNAME。

$ cat mystat.sql
select stn.NAME, vta.VALUE
  from V$MYSTAT vta, V$STATNAME stn
 where vta.STATISTIC# = stn.STATISTIC#
   and stn.NAME = '&name';

SQL> @mystat 
输入 name 的值:  redo size
原值    4:    and stn.NAME = '&name'
新值    4:    and stn.NAME = 'redo size'

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
redo size                                                                 0
SQL> insert into wwm select * from all_objects;

53817 rows inserted

SQL> / 
输入 name 的值:  redo size
原值    4:    and stn.NAME = '&name'
新值    4:    and stn.NAME = 'redo size'

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
redo size                                                                 12192184

SQL> insert /*+ APPEND */ into wwm select * from all_objects;

53817 rows inserted

SQL> / 
输入 name 的值:  redo size
原值    4:    and stn.NAME = '&name'
新值    4:    and stn.NAME = 'redo size'

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
redo size                                                                 12615332

看到APPEND插入用了12615332 - 12192184 = 423148 字节的REDO,比一般性插入要少很多。

除了上面的SQL,还可以使用Tom Kyte提供的Script.:

$ cat mystat.sql
set verify off
column value new_val V
define S="&1"
set autotrace off
select a.name, b.value
from v$statname a, v$mystat b
where a.statistic# = b.statistic#
and lower(a.name) like '%' || lower('&S')||'%'
/

$ cat mystat2.sql
set verify off
select a.name, b.value V, to_char(b.value-&V,'999,999,999,999') diff
from v$statname a, v$mystat b
where a.statistic# = b.statistic#
and lower(a.name) like '%' || lower('&S')||'%'
/

SQL> @mystat 'redo size'

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
redo size                                                                 0

也可以用下面这个PROCEDURE观察SQL消耗的REDO情况:

create or replace procedure do_sql(p_sql in varchar2) as
  l_start_redo number;
  l_redo       number;
begin
  select v$mystat.value
    into l_start_redo
    from v$mystat, v$statname
   where v$mystat.statistic# = v$statname.statistic#
     and v$statname.name = 'redo size';
  execute immediate p_sql;
  commit;
  select v$mystat.value - l_start_redo
    into l_redo
    from v$mystat, v$statname
   where v$mystat.statistic# = v$statname.statistic#
     and v$statname.name = 'redo size';
  dbms_output.put_line(to_char(l_redo, '9,999,999') ||
                       ' bytes of redo generated for "' ||
                       substr(replace(p_sql, chr(10), ' '), 1, 25) ||
                       '"...');
end;

用法就不多说了。

减少REDO

       既然REDO这么消耗资源,那我们能屏蔽REDO吗?显然不能,那我们能减少REDO吗?这是可以的(注意,9.2以后,可以用FORCE  LOGGING开关来控制是否强制REDO,如果YES,则不管NOLOGGING还是APPEND都是不起任何作用的,可以SELECT FORCE_LOGGING FROM V$DATABASE查看是否FORCE。另外需要明白,没有一个办法能彻底不记录REDO,只能是减少REDO。因为不管如何,数据字典总是要产生一些REDO的。

create table nologging as select xxx 新建的表没有原来表的索引和默认值,只有非空(not null)的约束素条件可以继承过来.
INSERT /*+ APPEND */ INTO target_tablename SELECT 如果运行此命令时还有对target_tablename的DML操作会排队在它后面,对OLTP系统在用的表操作是不合适的。快速插入数据可以指定append提示,但是需要注意 noarchivelog模式下,默认用了append就是nologging模式的。在archivelog下,需要把表设置程Nologging模式。

可以通过如下语句设置为NO FORCE LOGGING。

Alter database no force logging;
这两种方法转移数据时没有用SGA里数据缓冲区和事物处理的回滚段, 也不写联机事物日志,就象数据库装载工具SQLLOAD一样直接把数据写到物理文件。

REDO的问题

    有时,会在ALERT中发现
Thread 1 cannot allocate new log, sequence 1466
Checkpoint not complete
Current log# 3 seq# 1465 mem# 0: /home/ora10g/oradata/ora10g/redo03.log
       这问题出现在系统尝试reuse online redo log file但是却没有可用的。可能是由于DBWR没有完成(Checkpoint not complete)或ARCH没有完成。
       1,DBWR,用多DBWR  process,合理分布数据,
       2,增加REDO LOG FILE
       3,扩大REDO的大小
       4,让CHECKPOINT发生更频繁,可以减少block buffer cache,FAST_START_MTTR_TARGET, LOG_CHECKPOINT_INTERVAL,LOG_CHECKPOINT_TIMEOUT。(要考虑全面哟)

INDEX 对UNDO的影响

    INSERT只产生很少的UNDO,因为只需要记录ROWID就可以在ROLLBACK的时候UNDO。

    UPDATE一般排在第二位,因为一般不会UPDATE一条记录里的所有值。

    DELETE产生的UNDO是最多的,因为DELETE后UNDO需要保存所DELETE的整条记录。

    UNDO使用的大小和INDEX有很大关系。

SQL> select used_ublk
  2    from v$transaction
  3   where addr =
  4         (select taddr
  5            from v$session
  6           where sid = (select sid from v$mystat where rownum = 1));

 USED_UBLK
----------

SQL> update wwm w set w.created=sysdate where w.owner='TEST';

4073 rows updated

SQL>
SQL> select used_ublk
  2    from v$transaction
  3   where addr =
  4         (select taddr
  5            from v$session
  6           where sid = (select sid from v$mystat where rownum = 1));

 USED_UBLK
----------
        28

看到这次更新用了28个BLOCK去存储UNDO信息。

SQL> commit;

Commit complete

SQL> create index index_wwm on wwm(created);

Index created

SQL>
SQL> select used_ublk
  2    from v$transaction
  3   where addr =
  4         (select taddr
  5            from v$session
  6           where sid = (select sid from v$mystat where rownum = 1));

 USED_UBLK
----------

SQL> update wwm w set w.created=sysdate where w.owner='TEST';

4073 rows updated

SQL>
SQL> select used_ublk
  2    from v$transaction
  3   where addr =
  4         (select taddr
  5            from v$session
  6           where sid = (select sid from v$mystat where rownum = 1));

 USED_UBLK
----------
       139

SQL>

看到在有INDEX上做UPDATE会产生5倍左右的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表空间上不能建立任何数据对象。

Undo is also protected by Redo

insert into t (x,y) values (1,1);

update t set x = x+1 where x = 1;

delete from t where x = 2;

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9399028/viewspace-686436/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
鱼儿的学习空间

注册时间:2010-11-16

  • 博文量
    422
  • 访问量
    1754785