我们知道oracle的块清除有两种:
1:快速块清除(fast commit cleanout);
2:延时块清除(delayed block cleanout);
数据库块的最前面有一个“开销”空间(overhead),这里会存放该块的一个事务表,对于锁定了该块中某些数据的各个“实际”事务,在这个事务表中都有一个相应的条目。->http://www.2cto.com/database/201110/108943.html
1)首先当一个事务开始时,需要在回滚段事务表上分配一个事务槽;
2)在数据块头部获得一个ITL事务槽,该事务槽指向回滚段段头的事务槽;
3)在修改数据之前,需要在回滚段中记录前镜像信息,回滚段头事务槽指向该记录;
4) 锁定修改行,修改行锁定位(lb-lock block)指向ITL事务槽;
5) 数据修改可以进行。
COMMIT时候Oracle需要将回滚段上的事务表信息标记为非活动,以便空间可以重用;此外所做的一个操作是块清除(Block cleanout),如果事务修改的某些块还在缓冲区缓存中,会清除块首部的ITL事务信息(包括提交标志、SCN等)和锁定信息。
在与我们的事务相关的提交列表中,Oracle会记录已修改的块列表(每个列表可以有20个块指针),Oracle会根据需要分配多个这样的列表,直至达到某个临界点。如果我们修改的块加起来超过了块缓冲区缓存大小的10%,Oracle 会停止为我们分配新的列表。例如,如果缓冲区缓存设置为可以缓存3,000个块,Oracle 会为我们维护最多300个块。
COMMIT时,Oracle会通过这些列表找到块,如果块仍在块缓冲区中,Oracle会执行一个很快的清理,这叫做快速块清除(FAST BLOCK CLEANOUT)。
所以,只要我们修改的块数没有超过缓存中总块数的10%,而且块仍在块缓存区中(如果已经被写回到数据文件上再次读出该数据块进行修改成本过于昂贵),Oracle就会在COMMIT时清理这些块。否则,就会延迟块清除到下次访问该块的时候。通过延迟块清除(DELAYED BLOCK CLEANOUT)可以提高数据库的性能,加快提交操作。
所以如果执行一个大的INSERT、UPDATE或DELETE,影响数据库中的许多块,就有可能在此之后,第一个“接触”块的查询会需要修改某些块首部并把块弄脏,生成REDO日志,会导致DBWR把这些块写入磁盘。 (--所以说select 语句也有可能会产生redo日志)
如果Oracle不对块完成这种延迟清除,那么COMMIT的处理可能很长,COMMIT必须重新访问每一个块,可能还要从磁盘将块再次读入(它们可能已经刷新输出)。
在一个OLTP系统中,可能从来不会看到这种情况发生,因为OLTP系统的特点是事务都很短小,只会影响为数不多的一些块。
如果你有如下的处理,就会受到块清除的影响:
・ 将大量新数据批量加载到数据仓库中;
・ 在刚刚加载的所有数据上运行UPDATE(产生需要清理的块);
・ 让别人查询这些数据
比较好的做法是:在批量加载了数据后,通过运行DBMS_STATS实用程序来收集统计信息,就能自然的完成块清除工作。
下面我们来说一下“延时块清除”以及oracle-01555错误
首先要说明一点,oracle-01555错误是一个安全的错误,它不会造成数据丢失或者损坏,只是会让收到该错误的查询无法继续。
oracle-01555错误的原因:
1)undo太小
如果在一个查询(时间较长的查询)开始后,对表进行了dml操作,因为oracle的一致性读,那么查询就需要用到相应的回滚数据。但是因为查询的时间较长,在我们需要用那些回滚段来构造cr块时发现回滚段已经被其他数据覆盖了。这样就会报oracle-01555错误!
比较直观的解决方法是DBA告诉数据库应用最长的查询需要多长时间,并把UNDO_RETENTION设为这个值,同时相应增大undo表空间大小。
在此我给大家稍微介绍一下orale中UNDO_RETENTION这个参数。oracle回滚段中区有四种状态 active;inactive;expired;free
active表示事物还在活动;inactive表示事物已提交(区可用但是尽量避免使用);expired表示undo区可以被覆盖;free表示空闲的区
这里我们主要关注一下inactive和expired两个状态的区别,inactive表示事物已经提交,理论上此时区已经可以被重新使用,但是因为oracle的一致性读,所以我们可能还需要把inactive区中的数据再保留一段时间,保留多长时间由UNDO_RETENTION参数决定。在保留了UNDO_RETENTION时间后,区的状态就改成expired。 (--注意如果一个事物需要用回滚段,而回滚表空间中此时已经没有free,和expired状态的区,那么就算inactive区没有被保留够UNDO_RETENTION时间,也是可以被使用的)
2)延时块清除
这种情况比较少见,特别是在OLTP系统里,在OLAP系统里可能会碰到,解决方法是在每次大量的insert或update之后,记得用DBMS_STATS包扫描相关对象。
前面我已经说了为什么会有延时块清除,主要是为了提高事物的效率!
延迟清除的块的下一个读者,首先根据块中的记录的回滚信息去查找回滚段中记录的commit时的SCN,
但回滚段可能已回绕,找不到提交时的scn了,
但是,从回滚段中可以得到一个最小的提交scn并且该事务已经提交肯定小于这个从回滚段中还存在的最小scn。
那么oracle给这个块清除的事务分配一个从回滚段中找到的最小事务scn。
这虽然不准确,但是是安全的,对于数据访问也不构成影响。所以叫 upper bound ,猜测的一个scn的上限。
延迟清除的块在被select 时,如果读的select 的scn 比这个回滚段里面最小的scn 还要小的话(回滚段已回绕),那么在回滚段里面找不到数
据了,oracle 就没有办法判断select 的SCN 与被要清除的数据块的大小关系,于是ora-01555就出现了,这个时候oracle 就不知道数据块里面
的数据是不是是查询时刻需要的数据.
如果select scn 大于回滚段里面最小的scn 的话,那么oracle 就使用这个最小的scn 来做为这个事务的 scn 来更新块的itl ,从而完成块的清除.