undo用来干什么的? undo表空间
1.事物回滚:rollback
2. 查询一致性
3.flash back
实例的恢复时用到的回滚 ---undo读的是redo文件中的undo部分
Redo:是基于安全考虑的,会记录数据库的所有变化,主要用来做恢复
insert操作
undo:记录rowid即可
redo:记录rowid+value
delete操作
undo:rowid+value
redo:rowid
update操作
undo:操作之前的rowid+value
redo:操作之后的rowid+value
20:00 会话1开始了一个长达30分钟的查询
20:05 会话2开始了一个update并且提交了,其中的undo信息保存900s那么在20:20时候可以被覆盖
20:22 会话3update了会话2的那一行,导致会话2中的undo信息被覆盖
此时会话1在查询到会话2update的那一行数据是由于要查的是20:00开始的那一刻的数据,但是其undo又被覆盖了,此时就会产生ora-01555错误:快照过旧
普通数据块上面要留一个undo地址,如果地址被覆盖或则更改,假设普通数据快上面的数据被更改,但是还未提交,那么在查询普通块时,
会根据普通数据块记录的undo数据块进行一致读,但是undo块被覆盖,其上没有指向redo文件的指针,所以一致读失败。
create table t(x varchar2(10),y varchar2(10));
insert into t(x,y) values(1,1);------insert 语句。生成的undo足以使insert消失,生成的redo信息足以使这个插入再次发生
update t set x=x+1 where x=1;
delete from t where x=2;
select force_logging from v$database;-----YES
select log_mode from v$database;----archivelog
-----------------------------------------ITL----------------------------
create table testblock1(
id number,
name varchar(4)
) ;
插入3条数据然后提交:
insert into testblock1 values(1,'a');
insert into testblock1 values(2,'b');
insert into testblock1 values(3,'c');
commit;
select rowid,dbms_rowid.rowid_relative_fno(rowid) rel_fno,dbms_rowid.rowid_block_number(rowid) blockno from testblock1;
alter system dump datafile 4 block 142998;
oradebug setmypid
oradebug tracefile_name
SELECT d.VALUE
|| '/'
|| LOWER (RTRIM (i.INSTANCE, CHR (0)))
|| '_ora_'
|| p.spid
|| '.trc'
AS "trace_file_name"
FROM (SELECT p.spid
FROM v$mystat m, v$session s, v$process p
WHERE m.statistic# = 1 AND s.SID = m.SID AND p.addr = s.paddr) p,
(SELECT t.INSTANCE
FROM v$thread t, v$parameter v
WHERE v.NAME = 'thread'
AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,
(SELECT VALUE
FROM v$parameter
WHERE NAME = 'user_dump_dest') d;
-----Oracle什么情况下select会产生redo ?
1)快速块清除或者叫commit cleanout。事务提交的时候,oracle针对内存里的块
1)把数据块ITL ENTRY里flag的标记为U
2)设置commit scn在Scn/Fsc列。有了两个标记就可以告诉全世界这个事务已经提交。
但ITL ENTRY 的Lck标志和每个数据行头的lb(锁定位信息)并不会清除。
Oracle 做commit cleanout并不会产生日志,这个你可能会感到比较奇怪,
修改了块,但是却没产生日志。其实这个产生日志的过程在后面的完整的块清除的时候才做。
也就是我们下一次读取到这个数据块的时候。
2)延迟块清除。事务提交的时候,事务修改的块已经不在内存里了,
这个时候,Oracle不会再从磁盘把块读取到内存里做块清除,
而是在下一次读取数据块的时候,做块清除的动作。这个块清除的动作会产生Redo。
需要注意直接路径读取由于绕过了buffer_cache,读取过程直接在进程的私有PGA里来完成,
这个过程也会在进程私有的内存里构造CR块,虽然这个过程里也会有延迟块清除发生,
但是不会产生Redo,而且不会把“脏”数据写会到磁盘。这意味着,如果这个表一直被直接路径读取,
将会有许多的浪费的延迟块清除发生。11G针对大表的全表扫描,11G前并行扫描都会产生直接路径的读取。
但是直接路径读取即使遇到了需要做延迟块清除的块也不会产生Redo。
oracle 11g release 2新增的特性为--延迟段创建
这个时候使用create table 不会分配任何存储空间,一个区段都不会分配。要延迟到insert发生时才会真正创建段,回滚是,段将持久存储。
回滚过程中重不涉及重做日志,只有恢复和归档的时候才会读取重做日志。重做日志不是用来读的,是用来写的。oracle不会再正常的处理中读取重做日志。
ARCH读文件时,LGWR能写到另一个不同的设备中,就不存在重做日志竞争。
commit时,重做日志缓存组区就会被刷新输出,commit之后数据库做的操作就是:
为事务生成一个SCN
LGWR将所有余下的缓存重做日志条目写入磁盘,并把SCN记录到在线重做日志文件中,这是真正的commit,事务条目会从v$transaction中删除掉
v$lock记录的而所有的锁都会被释放
如果事务修改的某些块还在缓冲区中,则会议一种快速的模式访问并‘清理’
块清除就是指清除存储在块首部的锁相关的信息。
ROLLBACK之前,数据库可能已经完成的工作有:
已经在SGA生成UNDO段和已修改的块还有对应前两项的redo日志。同事也已经取得了全部锁
select force_logging from v$database;
在nologging状态的数据库并不是不生成redo信息,还是会有少量的redo信息来保护我们的数据字典,在一个archivelog模式下开启nologging一定要及时备份。
建立一个段或则索引时使用nologging那么以后再重建这些对象的时候将不会再生成redo信息。
块清除在commit时候一般会执行,如果未完成。那么在select的时候就会出现少量的redo信息,这将可能导致块变脏(因为本身并没有被修改,不脏),也将导致下一个检查点时将大量的块写至磁盘。
在OLTP数据库中一般不用考虑块清除,因为事务一般都很小,在commit时都会完成相应的块清除。
但是当你在数据仓库中,如果加载时候要对数据执行大量的update,那就要把块清除作为一个考虑对象了,认识到这一点就应该在update之后主动接触这些数据
日志竞争问题:commit太过于频繁,或则由于redo所在的设备硬件问题。
临时表:修改临时表中是的数据是不会记入到redo信息的,不过,会生成undo,所以临时表还会为undo信息生成一部分redo信息所以:
select 临时表和普通表产生的redo信息一个很少,一个很多
update 临时表和普通表 后者是前者的一半
delete 几乎相同
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30018455/viewspace-1416050/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/30018455/viewspace-1416050/