oracle redo与undo_笔记7:临时表和redo/undo
临时表和redo/undo
这一节只是回答这样一个问题:“关于生成修改日志,临时表是怎样做的?”
临时表不会为它们的块生成redo。因此,对临时表的操作不是可恢复的。修改临时表中的一个块时,不会将这个修改记录到重做日志文件中。不过,临时表确实会生成undo,而且这个undo会记入日志。因此,临时表也会生成一些。初看上去好像没有道理:为什么需要生成
undo?这是因为你能回滚到事务中的一个SAVEPOINT。可以擦除对临时表的后50个INSERT,而只留下前50个。临时表可以有约束,正常表有的一切临时表都可以有。可能有一条INSERT语句要向临时表中插入500行,但插入到第500行时失败了,这就要求回滚这条语句。由于临时表一般表现得像正常的表一样,所以临时表必须生成undo。由于undo数据必须建立日志,因此临时表会为所生成的undo生成一些重做日志。
在临时表上运行的SQL语句主要是INSERT和SELECT。INSERT只生成极少的undo(需要把块恢复为插入前的“没有”状态,而存储“没有”不需要多少空间),另外SELECT根本不生成undo。
建立一个小测试来演示使用临时表时生成的redo量,同时这也暗示了为临时表生成的undo量,因为对于临时表,只会为undo生成日志。采用配置相同的永久表和临时表,然后对各个表执行同样的操作,测量每次生成的redo量。这里使用的表如下:
sys@ORCL>create table perm
2 (x char(2000),
3 y char(2000),
4 z char(2000))
5 /
Table created.
sys@ORCL>create global temporary table temp
2 (x char(2000),
3 y char(2000),
4 z char(2000))
5 on commit preserve rows
6 /
Table created.
建立一个小的存储过程,它能执行任意的SQL,并报告该SQL生成的redo量。使用这个例程分别在临时表和永久表上执行INSERT、UPDATE和DELETE:
sys@ORCL>create or replace procedure do_sql(p_sql in varchar2)
2 as
3 l_start_redo number;
4 l_redo number;
5 begin
6 l_start_redo :=get_stat_val('redo size');
7 execute immediate p_sql;
8 commit;
9 l_redo :=get_stat_val('redo size')-l_start_redo;
10 dbms_output.put_line
11 (to_char(l_redo,'99,999,999') || 'bytes of redo generated for "' || substr(replace(p_sql,chr(10),' '),1,25) || '"...');
12 end;
13 /
Procedure created.
接下来,对PERM表和TEMP表运行同样的INSERT、UPDATE和DELETE:
sys@ORCL>set serveroutput on format wrapped
sys@ORCL>begin
2 do_sql('insert into perm
3 select 1,1,1
4 from all_objects
5 where rownum<=500');
6 do_sql('insert into temp
7 select 1,1,1
8 from all_objects
9 where rownum <=500');
10 dbms_output.new_line;
11 do_sql('update perm set x=2');
12 do_sql('update temp set x=2');
13 dbms_output.new_line;
14 do_sql('delete from perm');
15 do_sql('delete from temp');
16 end;
17 /
3,301,008bytes of redo generated for "insert into perm select 1"...
68,492bytes of redo generated for "insert into temp select 1"...
3,160,584bytes of redo generated for "update perm set x=2"...
2,094,500bytes of redo generated for "update temp set x=2"...
3,360,904bytes of redo generated for "delete from perm"...
3,226,384bytes of redo generated for "delete from temp"...
PL/SQL procedure successfully completed.
可以看到,
.对“实际”表(永久表)的INSERT生成了大量redo,而对临时表几乎没有生成任何redo。这是有道理的,对临时表的INSERT只会生成很少的undo数据,而且对于临时表只会为undo数据建立日志。
.实际表的UPDATE生成的redo大约是临时表更新所生成redo的两倍。同样,这也是合理的,必须保存UPDATE的大约一半(即“前映像”)。对于临时表来说,不必保存“后映像”(redo)。
.每个DELETE需要几乎相同的redo空间。这是有道理的,因为对DELETE的undo很大,而对已修改块的redo很小。因此,对临时表的DELETE与对永久表的DELETE几乎相同。
因此,关于临时表上的DML活动,可以得出以下一般结论。
.INSERT会生成很少甚至不生成undo/redo活动。
.DELETE在临时表上生成的redo与在永久表上生成的redo同样多。
.临时表的UPDATE会生成永久表UPDATE一半的redo
另外,还必须考虑临时表上的所有索引。索引修改也会生成undo,这会进一步生成redo。
sys@ORCL>create index perm_idx on perm(x);
Index created.
sys@ORCL>create index temp_idx on temp(x);
create index temp_idx on temp(x)
*
ERROR at line 1:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
sys@ORCL>truncate table temp;
Table truncated.
sys@ORCL>create index temp_idx on temp(x);
Index created.
sys@ORCL>@20131126.sql
3,259,784bytes of redo generated for "insert into perm select 1"...
1,171,632bytes of redo generated for "insert into temp select 1"...
3,372,328bytes of redo generated for "update perm set x=2"...
3,277,484bytes of redo generated for "update temp set x=2"...
3,356,580bytes of redo generated for "delete from perm"...
4,324,020bytes of redo generated for "delete from temp"...
PL/SQL procedure successfully completed.
与前面看到的结果大致相同,不过可以看到索引无疑会增加生成的redo。对全局临时表的INSERT原先几乎不生成任何redo,现在会生成3MB的redo。所有增加的redo都与为维护索引生成的undo有关。
有了以上了解,可能会避免删除临时表。可以使用TRANCATE,或者只是让临时表在COMMIT之后或会话终止时自动置空。这些方法都不会生成undo,相应地也不会生成redo。应该尽量避免更新临时表,除非由于某种原因必须这样做。把临时表主要用于插入和选择。采用这种方式,就能最优地使用临时表不生成redo的特有能力。
本文来源 我爱IT技术网 http://www.52ij.com/jishu/5268.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
