Oracle redo undo 学习,主要来自《Oracle编程艺术》 —by Firsouler 2021.1.13
重做日志是数据库的事务日志
--测量redo
set autotrace traceonly statistics;
insert into t_2021 as select * from all_objects;
undo“逻辑的”恢复到原来的样子,它无法撤销其他事务对当前块的更改。Oracle的回滚是相反动作,每个insert,是delete,每个delete,Oracle会做insert,update也是相反操作。如果回滚大事务,比较消耗数据库资源。
直接路径操作的undo生成机制会不一样,这种操作可能不生成或生成很少的undo数据
举例:
create table t_objects as select * from all_objects where 1=0;
set autotrace traceonly statustics
select * from t_objects;
insert into t select *from all_objects;
rollback;
select * from t_objects;
--回滚不撤销原来已经分配的块,
9.3 redo和undo如何协作
数据库缓冲区里面会有一些被修改过而未提交的数据块,在磁盘的重做日志里也会有一些为提交的与这些修改相关的redo信息,这样的状态对数据库来说,比较常见。
9.4 提交和回滚
commit的开销主要两个方面, 客户端与服务器直接的往返通信两会增大,每次提交时,都必须等待redo写入磁盘, 从而造成更多等待事件(log file sync)
执行commit,或如下操作:
- 为事务生成一个SCN
- LGWR将所有未写入磁盘的重做日志条目写至磁盘,并把scn记录到在线重做日志文件中。这一步后,事务的状态为提交,此时v$transaction中被“删除”。
- v$lock中会记录会话持有的锁,锁被释放。
- 如果事务修改的某些块还在缓冲区缓冲中,Oracle会快速的模式访问并“清理”.块清楚(block cleanout)指清除存储在数据块首部与锁相关的信息,实际是清除块上的事务信息。LGWR会在修改的同时以增量方式将日志缓冲区的内容写到磁盘上,避免了commit需要过长时间等待刷所有redo信息。
PL/SQL 异步提交,虽然在语句或存储块写了多次commit,最后只能一次日志写入,如果用Oracle11以上版本,可在PL/SQL内执行commit work write wait来避免使用提交优化
rollback时,还要做如下工作:
- 撤销所有修改,Oracle数据库会读取undo段,将undo数据应用到数据块,并将相应的undo条目标记为已应用。如果之前插入了一行,rollback会删除,其他操作一样。
- 会话持有的所有锁都被是否
commit比rollback工作量小的多,不要轻易回滚。
9.5 分析redo
force logging:所有操作记录日志,忽略(nologging)
supplemental logging:两种,库级和表级。基于重做的应用程序可能需要在重做日志文件中记录其他列。记录这些附加列的过程称为补充日志记录。
分析redo log文件
SQL> oradebug setmypid
SQL> oradebug unlimit
SQL> alter system dump logfile ‘C:\APP\CUIHUA\ORADATA\CUIHUA112\REDO03.LOG’ scn min 7518013947 scn max 7518013970;
SQL> oradebug tracefile_name
块清除
锁实际是数据的属性,它存储在块首部。
任何事务都会有一个提交列表,Oracle会通过这个列表来记录已修改的块。每个列表都会去跟踪20个数据块,Oracle会根据需要分配多个这样的列表,直至达到某个临界点。如果修改的块加起来超过块缓冲区的10%,Oracle会停止分配新的列表。如果修改的块没超过缓存总块数的10%,块仍在缓冲区中并且是可用的,Oracle会在提交时清理这些块。
select会产生redo,清除脏块信息。 例如db_chache_size 大小16M,2048*8K,表中插入了10000个块,提交。因为超过10%,有的已写入磁盘,提交时也无法清理所有脏块,在第一次查询时清理脏块。
如果一个块被修改,下一个会话访问时,会去查最后一个修改的这个块的事务是否还活动,如果该事务部活动,就会进行块清除。在块清除的过程中,Oracle会从块首部读出前一个事务所用的undo段,然后再去undo首部查看此事务是否提交,如果已提交,就会查提交时间。
临时表
- INSERT会产生很少甚至不产生undo/redo
- 临时表的update会生成永久表update大约一般的redo
- delete在临时表和永久表生成的redo一样多
12C之后,可以通过参数TEMP_UNDO_ENABLED 将临时表的undo放临时表空间上,当参数为TRUE,任何临时表的dml都会产生很少的redo
9.6分析undo
注意:必须把索引的维护也考虑在内,与有索引的列相比,对一个未加索引的列的更新不仅执行更快,生成的undo也会少的多。
v$transaction.used_ublk :显示事务当前使用了多少undo块
ora-01555
发生上述错误存在以下3个原因
- undo段太小,不足以支撑系统上执行的工作
- 程序跨commit获取数据
- 块清除
一些修改或插入的事务用undo段来获取一致的数据,还要用它以备将来事务失败时所带来的回滚,可能会导致ora-01555
大批量的update或insert会导致块清除,在这些操作后建议收集统计信息。