2,undo和redo
Undo
Oracle将所有的数据更改记录在undo,这些记录信息可以使oracle使用rollback来撤销更改操作。Undo的机制主要有两个目的:一是用来允许读不能阻塞写入,写入不能阻塞读,二是可以使事务能够rollback(回滚)。
事务能够产生undo(回滚),且产生的undo记录数量可以在动态性能视图V$transaction中得到。用一个例子来看看undo的产生:
SQL> set autocommit off;
SQL> insert into t_test_undo values (2,'asd');
1 row created.
SQL>
SQL> select used_urec from v$session s,v$transaction t where
2 s.audsid = sys_context('userenv','sessionid') and
3 s.taddr = t.addr;
USED_UREC
----------
1
上面的操作产生了1条undo记录,再看看一次插入多条记录的情况:
SQL> insert into t_test_undo
2 select rownum + 50000, object_name from all_objects where rownum < 51;
50 rows created.
SQL> SQL> select used_urec from v$session s, v$transaction t
2 where s.audsid=sys_context('userenv', 'sessionid') and
3 s.taddr = t.addr;
USED_UREC
----------
2
上面的语句也只产生了一条undo。
然后看看update的情形:
SQL> update t_test_undo a set a.b = 'asdsd' where a.a = 1;
1 row updated.
SQL> select used_urec from v$session s, v$transaction t
2 where s.audsid=sys_context('userenv', 'sessionid') and
3 s.taddr = t.addr;
USED_UREC
----------
3
这个update语句也产生了1个undo记录,再看看delete的情形:
SQL> delete from t_test_undo a where a.a <10;
2 rows deleted.
SQL> select used_urec from v$session s, v$transaction t
2 where s.audsid=sys_context('userenv', 'sessionid') and
3 s.taddr = t.addr;
USED_UREC
----------
5
可以看出,delete的每一条记录都产生了一个undo记录。
由此可以大概对比一下不同的语句产生的undo大小。
SQL>
SQL>
SQL> insert into t_test_undo values (10, 'asd');
1 row created.
SQL> select a.XIDUSN, a.UBAREC, a.UBABLK, a.USED_UBLK, a.USED_UREC
2 from v$transaction a;
XIDUSN UBAREC UBABLK USED_UBLK USED_UREC
---------- ---------- ---------- ---------- ----------
9 17 336 1 1
SQL> commit;
Commit complete.
SQL> select a.XIDUSN, a.UBAREC, a.UBABLK, a.USED_UBLK, a.USED_UREC
2 from v$transaction a;
no rows selected
SQL> update t_test_undo a set a.b = 'qwe' where a.a = 10;
1 row updated.
SQL> select a.XIDUSN, a.UBAREC, a.UBABLK, a.USED_UBLK, a.USED_UREC
2 from v$transaction a;
XIDUSN UBAREC UBABLK USED_UBLK USED_UREC
---------- ---------- ---------- ---------- ----------
7 6 2701 1 1
SQL> commit;
Commit complete.
SQL> delete from t_test_undo a where a.a = 10;
1 row deleted.
SQL> select a.XIDUSN, a.UBAREC, a.UBABLK, a.USED_UBLK, a.USED_UREC
2 from v$transaction a;
XIDUSN UBAREC UBABLK USED_UBLK USED_UREC
---------- ---------- ---------- ---------- ----------
3 25 1057 1 1
SQL> commit;
Commit complete.
SQL> insert into t_test_undo values (10, 'asd');
1 row created.
SQL> update t_test_undo a set a.b = 'qwe' where a.a = 10;
1 row updated.
SQL> delete from t_test_undo a where a.a = 10;
1 row deleted.
SQL> select a.XIDUSN, a.UBAREC, a.UBABLK, a.USED_UBLK, a.USED_UREC
2 from v$transaction a;
XIDUSN UBAREC UBABLK USED_UBLK USED_UREC
---------- ---------- ---------- ---------- ----------
2 38 10021 1 3
SQL>
一般来说,insert产生了最少的undo,因为insert行的反操作是delete行,只记录插入记录的rowid,delete因为需要把整行的前映像记录到undo,所以产生最多的undo,update需要记录行中被更新的字段部分的前映像,因此一般来说介于insert和delete之间。
回滚段可以说是用来保持数据变化前映像而提供一致性读和保证事务完整性的一段存储区域。当一个事务开始的时候,首先把变化前的数据和变化后的数据先写入日志缓冲区,然后吧变化前的数据写入回滚段,最后才在数据缓冲区中修改。
Undo segment头部包含记录了当前事务使用的undo segment信息的一张表。一系列事务只使用一个undo segment存储所有数据。许多并发的事务可以使用同一个undo segment。
再来看看与undo相关的ora-01555:
SQL> host oerr ora 1555
01555, 00000, "snapshot too old: rollback segment number %s with name \"%s\" too small"
// *Cause: rollback records needed by a reader for consistent read are
// overwritten by other writers
// *Action: If in Automatic Undo Management mode, increase undo_retention
// setting. Otherwise, use larger rollback segments
在相对稳定的数据库中,出现这个错误大多数时候是代码需要调整,或者由于业务需要在某一时段进行大批量的业务处理,而对一些较大的查询产生了影响。涉及到的undo的优化或者sql的优化在性能调整一章中详述。
Oracle的segment信息可以在dba_segments或者sys_dba_segs中查看,从下面的输出信息中可以看到几个比较重要的段对象,如table,index,rollback。
SQL> select distinct segment_type from sys_dba_segs;
SEGMENT_TYPE
------------------
LOBINDEX
INDEX PARTITION
TABLE PARTITION
NESTED TABLE
ROLLBACK
LOB PARTITION
LOBSEGMENT
INDEX
TABLE
CLUSTER
TYPE2 UNDO
11 rows selected.
Redo
与undo不同,undo是产生使操作撤销的信息,而redo是产生使操作重做的信息。Oracle的redo有两种:online redo log(联机),archivelog(归档)。
Lgwr循环的写入联机日志,当前日志日满后,lgwr写下一个日志。Lgwr总是在一下条件之一满足之时将缓冲重做日志写入磁盘:
1,每三秒;2,每当满1/3或1MB;3碰到任何事务commit;
在事务commit或者rollback之前往往已经完成了一下工作:
已经在sga中产生了回滚段记录,用于撤销
已经在sga中产生了修改数据块
已经在sga中产生了回滚和修改的重做,是的以上2个操作可以重做
根据lgwr的刷新特点,一部分数据可能已经刷新到了磁盘
已经获得了所有的锁定
当commit时,要做的工作如下:
为事务产生scn,lgwr写磁盘,释放锁定,访问修改事务块,并清除之。
当rollback时,要做的工作如下:
使用回滚段的数据来撤销修改,释放锁定。
同样的,dml对redo产生的影响也是能够测定的。
下列语句依次执行:
select a.SID, a.VALUE
from v$mystat a, v$statname b
where a.STATISTIC# = b.STATISTIC#
and b.NAME like 'redo_size';
insert into t_test_undo values (12, '123');
commit;
select a.SID, a.VALUE
from v$mystat a, v$statname b
where a.STATISTIC# = b.STATISTIC#
and b.NAME like 'redo_size';
update t_test_undo a set a.b = '321' where a = 12;
commit;
select a.SID, a.VALUE
from v$mystat a, v$statname b
where a.STATISTIC# = b.STATISTIC#
and b.NAME like 'redo_size';
delete t_test_undo where a.a = 12;
commit;
select a.SID, a.VALUE
from v$mystat a, v$statname b
where a.STATISTIC# = b.STATISTIC#
and b.NAME like 'redo_size';
得到的redo size数值如下表:
操作 | Sid | Redo size |
初始 | 144 | 0 |
Insert 一行 | 144 | 548 |
Update 一行 | 144 | 1140 |
Delete 一行 | 144 | 1732 |
同样可以测试一次插入多行,更新多行和删除多行对redo的产生量,并且可以测试逐条提交和一次提交对redo的产生量。如果不结合起来看undo和redo的影响而来调整应用,很多时候结果往往是不确定的。值得注意的是触发器的不同类型对redo的产生也有影响,比如对update使用after触发器,将不会影响重做。开发过程中,可以大致了解一下重做的数量:估计事务的大小,需要修改的数据量,提交的频率,dml类型占比(考虑到update产生大约2倍的重做,insert和delete大约为1倍)。而以上的表中似乎看不到不同dml对redo的区别,这是因为b的字段类型为varchar2(20),本身的修改量很小,如果吧字段修改为char(2000),则数字规律很明显,有关字符类型的细节在数据库设计一章节中详述。
另外redo是备份和恢复的一个支撑原理。有关联机日志和归档日志的管理和使用在备份恢复一章中详解。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16179598/viewspace-662794/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/16179598/viewspace-662794/