未commit的数据会不会写入磁盘,这个比较模糊。磁盘的意思是写入日志文件还是写入数据文件(数据load上来的地方)?
事务的commit这个动作,Oracle首先不是将数据从数据库缓冲区中刷到磁盘里面,而是先将修改数据的这些动作写成redo也就是重做日志了。
至于Oracle何时会将数据从数据缓冲区中刷到磁盘上,是由DBWR进程来进行的,而DBWR又是由CKPT检查点进程来决定何时工作的。
这里可以大概说一下,数据缓冲区中有两个列表,一个是写入列表,一个是最近最少使用列表。在数据缓冲区里面的数据写入到磁盘的这个过程,其实就是数据从写入列表中写入到磁盘的过程。
所以说,一般情况下事务未提交,数据是不会写到磁盘(原数据地方)上面去的。但是commit之后,是否有写到磁盘上,就不一定了,需要等待dbwr写,就是迟早会写。
另外,如果一个事务调取了这部分的数据进行了修改,但是没有commit,另外一个事务也正在调取这部分数据(事务很多导致buffer busy wait不是free buffer wait),那么由于前一个事务的修改还没有提交,所以新事务看到的数据还是未修改之前的。其实这个就是所谓的“读一致性”,这是Oracle数据库重要的特征之一。Oracle数据库通过undo来实现“读一致性”的功能。
上面的情况只是针对一般情况,但是如果一个SGA只有 1G大小下修改1TB的表数据,修改的数据量很多,超过了buffer cache 或者buffer cache不足时,checkpoint进程会通知dbwr写未commit的脏数据到磁盘上 。但是写之前会先通知LGWR将redo写入redo log,所以说LGWR永远在DBWR之前是成立的。
大量的脏数据写入datafile后,如果事务commit了(commit完成前应该有两个动作:1,通知lgwr写日志;2 ,清理那些修改过的数据块、和对应UNDO块上面ITL事务的信息(这是我们一般不深入了解的)),这就涉及到了block delayed cleanout (延迟块清除介绍)。 使用delayed cleanout,Oracle不用将那些脏数据在LOAD回Buffer Cache修改块上的ITL信息,但要将之前和事务相关的UNDO块头(不是UNDO块,所以commit很快)上的ITL信息清理。这样当数据块再次被LOAD进Cache时,oracle会发现此块上ITL信息还没有清理完,oracle会按ITL上信息查找对应的UNDO块头ITL,如果发现UNDO头上ITL已经被清理,说明上个事务已经COMMIT了,这时再清理数据块上的ITL信息。
上面相对应的情况,脏数据写入datafile后,如果事务Rollback了,那么这时候就需要将之前的块load进Cache 后rollback回去了。这个是非常耗时的,如果之前的事务运行了几天,那么我们就会发现用户的对话框一直不可用,不向Commit那样,基本瞬间完成。 这时用户一般不愿等rollback完成,直接关闭连接界面。此时是不是Oracle就不回滚了呢,肯定不行的。我们这时就会发现Oracle在后台由PMON后台进程接管rollback继续进行。 这时有些开发人员再次重复操作的时候,他就会发现他对之前那些块的操作时,可能会被锁。他会找上DBA过来问你,那个数据库现在是不是性能有问题啊,为什么我被锁住了。这时候我们可以根据PMON信息,找到他之前连上数据库的操作信息。他看后就知道到问题是由于他引起的了。这也说明,我们在进行数据操作时,运行了好几天的事务最好不要中途rollback,测试环境尽量commit吧。
正因为数据库中commit操作多过rollback操作,delayed cleanout还是可以显著提高数据库性能的。
commit scn
ITL
undo segment header
alter system flush buffer_cache;