ORACLE UNDO 和 REDO、直接路径操作append

1. REDO(重做信息)

Redo log file(重做日志文件),是数据库的事务日志。

Oracle维护着两类重做日志文件:在线(online)重做日志文件和归档(archived)重做日志文件,这两类重做日志文件用于实例失败或是介质失败时数据的恢复;

如果数据库所在主机突然断电导致实例失败,则Oracle会使用在线重做日志将系统恰好恢复到掉电之前的时间点;

如果硬盘出现故障(即介质失败),Oracle会使用归档重做日志和在线重做日志将硬盘上的数据恢复到适当的时间点;

另外如果你无意地上除了某些重要信息并提交了这个操作,那么可以恢复受影响数据的一个备份,并使用在线和归档重做日志文件把它恢复到之前的一个时间点;

重做日志文件可能是数据库中最重要的恢复结构,但同时其他部分(如undo段、分布式事务恢复等)也不可或缺,重做日志是数据库区别于传统文件系统的一个重要特征;

2. UNDO(撤销信息)

当对数据执行DML(增、删、改)时,数据库会生成undo信息,万一你执行事务或语句由于某些原因失败时,或者你用一条语句rollback语句请求回滚时,数据库就可以利用这些undo信息将数据返回到修改前的样子。

3. REDO 和 UNDO 区别

① Redo用于在失败时恢复事务,undo用于取消一条语句或者一组语句的作用;

② Undo信息存储在数据库内部一组特殊段中(undo segment);

③ Undo并不是使数据库物理地回复到执行语句或者事务之前的样子,数据库只是逻辑地回复到原来的样子,所有的修改都被逻辑地取消,但是数据库结构以及数据库块在回滚后可能还与回滚前保持一致;

因为在多用户系统中,可能会有数百或者上千个并发事务,不仅仅你的事务在修改一些块,其他许多人的事务也可能在修改这些块,因此,不能简单地将一个块放到你事务开始前的样子,这样很可能会撤销其他人的事务工作。

例如:

假设你的事务执行了一个insert语句,这条语句导致分配了一个新的区段;

通过执行这个insert,你将会获得一个新的数据库块,并在格式化该块后在其中放入一些数据;

此时,可能出现另外的事务,它也往这个块中插入数据;如果你要回滚你的事务,显然蹦年取消对这个数据块已有的格式化和空间分配,否则会影响到另外的那个事务的工作。

因此回滚是,Oracle实际上会做与之前逻辑上相反的工作,即:

对于每个insert,会执行一个delete;

对于每个delete,会执行一个insert;

对于每一个update,会执行一个“反update”,或者执行另一个update将修改前的行放回去;

还有一点需要特别注意:undo对于直接路径操作(即使用append提示进行insert)不适用,直接操作能绕过表上的undo生成。

4. 扩展阅读:直接路径操作

4.1 直接路径操作在高水位线以外分配空间,绕过了数据缓冲区,直接将数据插入表所在的数据文件中;

① 准备示例数据表

create table student(

stu_id varchar2(4),

stu_name varchar2(100), --姓名

sex varchar2(1),  --性别 1 男  2 女  0 未知

credit integer default 0

);

create table student_temp as select * from student where 1=2;

② 往student表插入数据并提交

insert into student (stu_id, stu_name, sex, credit) values ('0001', '大王', '2', '83');

insert into student (stu_id, stu_name, sex, credit) values ('0002', '刘一', '1', '85');

commit;

查看student表中数据占用的数据块,现在student表中有两行数据,占用数据库70460。

select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from student;

 

查看Buffer cache中student表所占用的缓存。当前包含数据的块70460。

select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='STUDENT');

 

由于对AA表进行了全表扫描,因此,AA表中高水点下的所有块都被读进了Buffer cache。

③ 使用直接路径插入,并提交

insert /*+ append*/ into student_temp select * from student;

commit;

查看student_temp表中数据占用的数据块,现在student_temp 表中有两行数据,占用数据库70476。

select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from student_temp;

 

Buffer cache中student_temp表所占用的缓存,不包含数据块70746。

select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='STUDENT_TEMP');

 

几秒钟后在查看缓存中数据,才包含70746(这个是为什么?

select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='STUDENT_TEMP');

 

④ 正常插入

insert  into student_temp select * from student;

commit;

查看student_temp表中数据占用的数据块,现在student_temp 表中有四行数据,新数据占用数据库70478。

select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid) from student_temp;

 

Buffer cache中student_temp表所占用的缓存,不包含数据块70748。

select file#,block# from v$bh where objd=(select data_object_id from user_objects where object_name='STUDENT_TEMP');

 

4.2 直接路径操作不产生redo和undo log,依赖高水点实现回滚。

4.3 直接路径插入的时候Oracle会维护索引,为了避免索引的性能影响,可以先删除索引,等插入完成后重新建立。

4.4 直接路径插入回答导致对被插入的表加表级锁,在提交之前,别会话不能再对此表进行insert、delete、update等操作。

① 在同一个会话执行insert,不提交,然后执行select操作

insert into student (stu_id, stu_name, sex, credit) values ('0003', '陈二', '2', '86');

select * from student_temp;

 

② 换一个会话可以正常执行select操作。

分区索引:https://www.cnblogs.com/Dreamer-1/p/6132776.html

直接操作路径:https://blog.csdn.net/rudygao/article/details/40296679

猜你喜欢

转载自www.cnblogs.com/wangrui1587165/p/9505216.html