作者:刘晓峰
原文链接:http://www.tdpub.cn/Blog/detail/id/1294.html
1.什么时机产生UNDO和REDO
有DML就会产生UNDO,有UNDO就会产生此UNDO对应REDO
执行DML,再执行COMMIT是把位于内存的日志缓存区数据转储到磁盘的在线重做日志组
执行了COMMIT,不一定会修改磁盘数据,磁盘数据的DBWn进程触发机制不依赖COMMIT.
UNDO是回滚段,磁盘上
测量REDO是测量REDO LOG FILE 还是 REDO BUFFER ?虽然他们的结果应该是相等的
2.什么样的操作不会产生UNDO和REDO?
UNDO用于事务回滚,所以DML语句一般都会产生UNDO(直接路径加载+nologging不会产生或者产生很少的UNDO和REDO)
REDO用于事务恢复,临时表上的数据用完即丢,所以临时表上的DML不产生REDO,但是临时表发生DML的时候会产生UNDO(因为临时表上也可以执行rollback,有回滚就肯定有UNDO),这部分UNDO会产生REDO
3.临时表最好只进行INSERT 和SELECT
原因:
虽然临时表本身的操作不会产生REDO,会产生UNDO以及这部分UNDO的REDO,所以如何减小UNDO,DELETE产生的UNDO最多,而UPDATE对索引影响比较大,因此如果临时表上有索引,此部分索引的修改也会产生UNDO,也会针对这部分UNDO产生REDO
4.如何最小化临时表的REDO产生
ALTER SYSTEM/SESSION SET TEMP_UNDO_ENABLED =TRUE
前面我们知道临时表的操作,UNDO产生不能避免,不过还是会产生一点点REDO,能不把这一点点REDO也去掉。
我们知道临时表的操作是发生在临时表表空间,临时表空间的DML操作不会产生REDO。是临时表空间的UNDO会产生REDO,原因是UNDO是放在UNDO表空间,如果我们把临时表对应的UNDO也放在临时表空间,而不是UNDO表空间,那么这一点点REDO也不会产生了
5.测量开启 TEMP_UNDO_ENABLED前后的REDO,UNDO变化
结论:临时表写入1M数据。开启TEMP_UNDO_ENABLED之后,事务产生的REDO从140K降低为0.1KB
--为了方便换算,写1m的数据进行测试
create global TEMPORARY TABLE tem_test(a varchar2(1024)) on commit preserve rows ;
--创建普通表
create TABLE tem_test_normal(a varchar2(1024)) ;
--简单起见只测量insert,DML中insert最多的REDO,最少的UNDO,UNDO数量级应该和存储ROWID需要的字节量一致
--使用跟踪打印出来的redo更准确
--==========================================================
--新开窗口1--START
begin
for i in 1..1024 loop
insert into tem_test(a)values(rpad('X',1024,'X'));
end loop;
end;
--redo 632->151716 :0.14m redo
SELECT a.name
,b.value
FROM v$statname a
,v$sesstat b
WHERE a.statistic# = b.statistic#
AND A.NAME = 'redo size'
AND B.SID=USERENV('SID')
--事务产生的undo 0-73728:0.07m UNDO
SELECT t.used_ublk*8*1024
FROM v$session s
,v$transaction t
WHERE s.saddr = t.ses_addr
AND s.sid = userenv('SID');
--新开窗口1---END
--==========================================================
--新开窗口2---START
ALTER SESSION SET TEMP_UNDO_ENABLED =TRUE;
begin
for i in 1..1024 loop
insert into tem_test(a)values(rpad('X',1024,'X'));
end loop;
end;
--redo 676->948 : 很少
SELECT a.name
,b.value
FROM v$statname a
,v$sesstat b
WHERE a.statistic# = b.statistic#
AND A.NAME = 'redo size'
AND B.SID=USERENV('SID')
--事务产生的undo 0-8192:8KB UNDO
SELECT t.used_ublk*8*1024
FROM v$session s
,v$transaction t
WHERE s.saddr = t.ses_addr
AND s.sid = userenv('SID');
--查询
select * from v$tempundostat
--新开窗口2---END
--==========================================================
--新开窗口3---START
begin
for i in 1..1024 loop
insert into tem_test_normal(a)values(rpad('X',1024,'X'));
end loop;
end;
--redo 676->1435724 :1.36m redo
SELECT a.name
,b.value
FROM v$statname a
,v$sesstat b
WHERE a.statistic# = b.statistic#
AND A.NAME = 'redo size'
AND B.SID=USERENV('SID')
--事务产生的undo 0-81920: 80k UNDO
SELECT t.used_ublk*8*1024
FROM v$session s
,v$transaction t
WHERE s.saddr = t.ses_addr
AND s.sid = userenv('SID');
--新开窗口1---END
select sum(lengthb(rowid))/1024||'KB' from tem_test_normal;--应该是10K-100K左右
--=========================================================