ck_read_count来设置一次读入块的个数)
说明:
在预处理的数据已经缓存在db buffer或刚刚被从数据文件读入到db buffer中,就要根据sql语句的类型来决定接下来如何操作。
1>. 如果是select语句,则要查看db buffer块的头部是否有事务,如果有事务,则从回滚段中读取数据;如果没有事务,则比较select的scn和db buffer块头部的scn,如果前者小于后者,仍然要从回滚段中读取数据;如果前者大于后者,说明这是一非脏缓存,可以直接读取这个db buffer块的中内容。
2>. 如果是DML操作,则即使在db buffer中找到一个没有事务,而且SCN比自己小的非脏缓存数据块,服务器进程仍然要到表的头部对这条记录申请加锁,加锁成功才能进行后续动作,如果不成功,则要等待前面的进程解锁后才能进行动作(这个时候阻塞是tx锁阻塞)。
6.用户commit或rollback
到现在为止,数据已经在db buffer或数据文件中修改完成,但是否要永久写到数文件中,要由用户来决定commit(保存更改到数据文件)和rollback(撤销数据的更改),下面来看看在commit和rollback时,oracle都在做什么。
用户执行commit命令
只有当sql语句所影响的所有行所在的最后一个块被读入db buffer并且重做信息被写入redo log buffer(仅指日志缓冲区,而不包括日志文件)之后,用户才可以发去commit命令,commit触发lgwr进程,但不强制立即dbwr来释放所有相应db buffer块的锁(也就是no-force-at-commit,即提交不强制写),也就是说有可能虽然已经commit了,但在随后的一段时间内dbwr还在写这条sql语句所涉及的数据块。表头部的行锁并不在commit之后立即释放,而是要等dbwr进程完成之后才释放,这就可能会出现一个用户请求另一用户已经commit的资源不成功的现象。
A .
从Commit和dbwr进程结束之间的时间很短,如果恰巧在commit之后,dbwr未结束之前断电,因为commit之后的数据已经属于
数据文件的内容,但这部分文件没有完全写入到数据文件中。所以需要前滚。由于commit已经触发lgwr,这些所有未来得及写入数据文件的更改会在实例重启后,由smon进程根据重做日志文件来前滚,完成之前commit未完成的工作(即把更改写入数据文件)。
B.
如果未commit就断电了,因为数据已经在db buffer更改了,没有commit,说明这部分数据不属于数据文件,由于dbwr之前触发lgwr(也就是只要数据更改,肯定要先有log),所有DBWR在数据文件上的修改都会被先一步记入重做日志文件,实例重启后,SMON进程再根据重做日志文件来回滚。
其实smon的前滚回滚是根据检查点来完成的,当一个全部检查点发生的时候,首先让LGWR进程将redo log buffer中的所有缓冲(包含未提交的重做信息)写入重做日志文件,然后让dbwr进程将db buffer已提交的缓冲写入数据文件(不强制写未提交的)。然后更新控制文件和数据文件头部的SCN,表明当前
数据库是一致的,在相邻的两个检查点之间有很多事务,有提交和未提交的。像前面的前滚回滚比较完整的说法是如下的说明:
A.
发生检查点之前断电,并且当时有一个未提交的改变正在进行,实例重启之后,SMON进程将从上一个检查点开始核对这个检查点之后记录在重做日志文件中已提交的和未提交改变,因为dbwr之前会触发lgwr,所以dbwr对数据文件的修改一定会被先记录在重做日志文件中。因此,断电前被DBWN写进数据文件的改变将通过重做日志文件中的记录进行还原,叫做回滚,
B.
如果断电时有一个已提交,但dbwr动作还没有完全完成的改变存在,因为已经提交,提交会触发lgwr进程,所以不管dbwr动作是否已完成,该语句将要影响的行及其产生的结果一定已经记录在重做日志文件中了,则实例重启后,SMON进程根据重做日志文件进行前滚
实例失败后用于恢复的时间由两个检查点之间的间隔大小来决定,可以通个四个参数设置检查点执行的频率:
Log_checkpoint_interval:决定两个检查点之间写入重做日志文件的
系统物理块(redo blocks)的大小,默认值是0,无限制
log_checkpoint_timeout: 决定了两个检查点之间的时间长度(秒),默认值是1800s
fast_start_io_target:决定了用于恢复时需要处理的块的多少,默认值是0,无限制
fast_start_mttr_target:直接决定了用于恢复的时间的长短,默认值是0,无限制
(SMON进程执行的前滚和回滚与用户的回滚是不同的,SMON是根据重做日志文件进行前滚或回滚,而用户的回滚一定是根据回滚段的内容进行回滚的。在这里要说一下回滚段存储的数据,假如是delete操作,则回滚段将会记录整个行的数据,假如是update,则回滚段只记录被修改了的字段的变化前的数据(前映像),也就是没有被修改的字段是不会被记录的,假如是insert,则回滚段只记录插入记录的rowid。这样假如事务提交,那回滚段中简单标记该事务已经提交;假如是回退,则如果操作是delete,回退的时候把回滚段中数据重新写回数据块,操作如果是update,则把变化前数据修改回去,操作如果是insert,则根据记录的rowid 把该记录删除。)
用户执行rollback
如果用户rollback,则服务器进程会根据数据文件块和DB BUFFER中块的头部的事务列表和SCN以及回滚段地址找到回滚段中相应的修改前的副本,并且用这些原值来还原当前数据文件中已修改但未提交的改变。如果有多个“前映像”,服务器进程会在一个“前映像”的头部找到“前前映像”的回滚段地址,一直找到同一事务下的最早的一个“前映像”为止。一旦发出了COMMIT,用户就不能rollback,这使得COMMIT后DBWR进程还没有全部完成的后续动作得到了保障。
到现在为例一个事务已经结束了。
说明:
TM锁:符合lock机制的,用于保护对象的定义不被修改
TX锁:这个锁代表一个事务,是行级锁,用数据块头、数据记录头的一些字段表示,也是符合lock机制,有resource structure、lock structure、enqueue算法。
----end----
|