Oracle还是比较常用的,于是我研究了一下Oracle COMMIT,在这里拿出来和大家分享一下,希望对大家有用。只有当SQL语句影响的所有行所在的***一个块被读入DB BUFFER并且重做信息被写入REDO LOG BUFFER之后,用户才可以发出COMMIT,Oracle COMMIT触发LGRW,但并不强制立即DBWN来释放所有相应的DB BUFFER块上的锁,但在随后的一段时间内DBWN还在写这条语句涉及的数据块的情形,表头部的行锁,并不是在COMMIT一发出就马上释放,实际上要等到相应的DBWN进程结束才会释放。
一个用户请求锁定另一个用户已COMMIT的资源不成功的机会是存在的。Oracle COMMIT发出后会将回滚段中的"前映像"标识为已提交.DML语句会产生一个SCN号,DBWN触发时写入到数据块的头部,COMMIT时也会产生一个SCN号,也会被写入数据块的头部。在数据块的头部只存储一个***的SCN号,COMMIT之后这个事务插槽可以被另外一个事务使用。如果用户ROOLBACK,则服务器进程会根据数据文件块和DB BUFFER中块的头部的事务列表和SCN以及回滚段地址重构出相应的修改前的副本,并且用这些原值来还原当前数据文件中已修改但未提交的改变。如果有多个"前映像",服务器进程会在一个"前映像"的头部找到"前前映像"的回滚段地址,一直重构出同一事务下的最早的一个"前映像"为止。一旦发出了COMMIT,用户就不能ROLLBACK,这使得COMMIT后DBWN进程还没有全部完成的后续动作得到了保障。
下面我们要提到检查点的作用,ckpt的触发,有以下几种情况:
1.当发生日志组切换的时候
2.当满足log_checkpoint_timeout、log_checkpoint_interval、fast_start_io_target、fast_start_mttr_target参数设置的时候
3.当运行alter system switchlogfile的时候
4.当运行alter systemckeckpoint的时候
5.当运行altertablespacetbs_namebegin backup[end backup]的时候
6.当运行altertablespace[datafile] offline的时候
7.系统正常关闭时
只有在4.7两种情况下发生完全检查点。发生完全检查点时,首先系统记录检查点对应的Checkpoint SCN,并记录下该时刻修改的DB BUFFER对应的日志文件的***的重做字节地址(Redo Byte Address (RBA)),然后DBWN进程将这个重做字节地址(RBA)之前已发生的DB BUFFER中的脏缓冲写入数据文件(之所以要以重做字节地址(RBA)为标志是因为在检查点发生到检查点完成之间的时间内,系统还在一直不断的产生修改,这些修改所产生的DB BUFFER脏缓冲,以及日志条目将不会影响这次检查点***确认的一致性结果,也就是***确认这个Checkpoint SCN之前的系统是一致的)。
***把Checkpoint SCN和RBA更新至控制文件,Checkpoint SCN更新至每个数据文件头部,表明当前数据库是一致的。日志切换并不导致一个完全检点的发生,比如有三个日志文件组,当发生日志切换时发生检查点,而发生日志切换一般是因为当前的LGWR正在写重做日志,也就是LGWR当刚写满2号日志就立即触发检查点,于是系统开始核对3号日志中记录的REDO项目所对应的数据是否已经从DB BUFFER中写入数据文件(不管事务是否已提交),如果没有写入,检查点就触发DBWN进程将这些缓冲块写入数据文件,显然LGWR因此而发生等待,除此以外,检查点还让DBWN进程将在2号日志中对应修改的DB BUFFER块写入数据文件,然后继续LGWR进程,直到LGWR进程将LGWR触发之前存在于REDO LOG BUFFER中的所有缓冲(包含未提交的重做信息)写入重做日志文件,检查点再更新数据文件,控制文件头部SCN。其实LGWR等待的并不是CKPT的完成,而是等待CKPT触发的DBWN进程的完成。
可以想像断电时可能既有未COMMIT的事务,也可能同时存在已COMMIT但DBWN未完成的情况,如果断电时有一个已COMMIT但DBWN动作没有完成的情况存在,因为已经COMMIT,COMMIT会触发LGWR进程,所以不管DBWN动作是否已完成,该语句将要影响的行及其产生的结果一定已经记录在重做日志文件中了,则实例重启后,SMON进程从控制文件中记录的上一次重做字节地址(RBA)开始,按照重做日志文件中的条目对数据文件和回滚段重新做一遍即前滚,注意这些条目的操作在断电之前有的已经被DBWN写入了数据文件,有的还没有来得及写,不管有没有写进数据文件,前滚时都会再重新写一次(9I之前是这样的),9I之后,由于也在日志中记录了DBWN改写的块信息,系统会过滤掉已写入的条目而只重做那些未写入的条目。对于一个未提交事务,分几种情况来描述:
1)LGWR与DBWN一致的情况即一个语句执行完成后很长时间也没有COMMIT,这种情况一般不存在DBWN来不及完成的情况。只是没有Oracle COMMIT而已。那么SMON将在前滚完成后,利用回滚段重构出具有最小SCN的前映像,并把它的值写回原位。
2)事务执行中断电,即可能存在LGWR与DBWN不同步的情况(因为DBWN之前会触发LGWR,所以DBWN对数据文件的修改一定会被先记录在重做日志文件中。因此只可能存在已写入重做日志而未来得及写入数据文件的情况存在。而不可能存在已写入数据文件却没有写入日志文件的情况。),这种情况下SMON也会先前滚一点(即把数据文件与相应的日志文件先同步再回滚,之所以说前滚一点,是指仅LGWR与DBWN之间进度的差距,而不是把这条语句进行到底再回滚,因为日志文件中记录的是执行语句操作的一个个块的修改信息,而不只是记录一条执行语句的字面内容),然后利用回滚段重构出具有最小SCN的前映像,并把它的值写回原位。由此可见,实例失败后用于恢复的时间由两个检查点之间的间隔大小来决定,我们可以通个四个参数设置检查点执行的频率,LOG_CHECKPOINT_IMTERVAL决定了两个检查点之间写入重做日志文件的系统物理块的大小,LOG_CHECKPOINT_TIMEOUT决定了两个检查点之间的时间长度,FAST_START_IO_TARGET决定了用于恢复时需要处理的块的大小,FAST_START_MTTR_TARGET直接决定了用于恢复的时间的长短。
检查点的作用就是不断的确认LGWR与DBWN之间的同步情况,以便实例失败后从上一个检查点开始恢复,问题是两个检查点之间LGWR与DBWN大部分的操作是同步的,只是一小部分没有同步,这种传统的检查点使实例恢复做了比较多的无用功,因此,ORACLE引入了增量检查点,增量检查点会在上一次传统检查点发生后到下一次传统检查点发生之前,不断的更新记录在控制文件中重做字节地址(RBA)(CKPT进程每三秒更新一次,见下面DBWN讲述),这样实例失败后将直接从控制文件中记录的***更新的重做字节地址(RBA)开始进行前滚和回滚,这就省略掉了恢复时大部份的重做日志的重做(即使在9I以后的版本里也省略掉了大部分的过滤重做日志条目的时间)。(对以上描述做一个简单的比喻:比如一个贸易公司下设经营部、货运部、监督部,经营部负责贸易合同的签订与记录,货运部负责按合同号的顺序把货物送达,监督部负责定期检查确认经营部签订的合同与货运部货物送达情况之间的同步情况,监督部每月检查一次,每次检查时,先确认当时正在装车的货物的合同号,并要求货运部把在这个合同号之前的所有还存在临时仓库中的未送货物全部送达。等货运部完成监督部下达的任务后,监督部在检查本上记录下本次开始检查时那票正在装车的货物的合同号,本次检查完成。如果这个公司发生了一次人事大换血,公司重新开业后,监督部就会从检查本上记录的合同号开始,检查在这之后所有发生的合同及货物送达情况,要求货运部把所有客户确认的但还未送达的货物送达。以上介绍Oracle COMMIT。
【编辑推荐】