在oracle中的commit经常使用,但是commit前后数据库内部所做的事情还是很值得推敲的。网友又提到了一个dml语句,没有commit会产生redo吗,产生redo肯定是的,而且在commit之前已经产生了大量的redo。
SQL> select name,value from v$mystat a,v$statname b where a.statistic#=b.statistic# and name='redo size';
NAMEVALUE
---------------------------------------------------------------- ----------
redo size1372
SQL> insert into test01 values(1,'pom');
1 row inserted
SQL> select name,value from v$mystat a,v$statname b where a.statistic#=b.statistic# and name='redo size';
NAMEVALUE
---------------------------------------------------------------- ----------
redo size1724
其实如果此时commit或者rollback都会产生redo。Redo是记录block变化的信息的。
没有执行commit的dml时数据库已经做了大部分工作,其实即使大事务的dml时,commit执行上也很平滑,commit之前很多工作已经完成了。
Dml时数据库中:
1修改sga中buffer cache,有数据块的修改,可能同时有表段块的修改和索引块的修改。
2 sga中关于undo块的生成,表的flashback都是利用undo tablespace中的前镜像来实现的。
3同样redo log buffer产生了包含上述数据块的变化的redo信息。
4 buffer cache中可能有部门数据已经写入到磁盘。
5获得需要的锁。
刚开始误解不commit的数据块是不会写入到磁盘的,commit时只是会触发LGWR,把undo所在回滚段标记为已提交。
dml时会产生一个scn号,dbwr触发会写入到数据文件头部,commit时产生scn号,同样写入数据块头部。不过数据块头部只存储了最新的scn号。
根据block的定义,block中存储了事务插槽,事务期间都会占用这个block的事务插槽,commit后事务结束,事务插槽可以被另外对此数据块的事务使用。
Commit时数据库内部:
1事务生成scn
2根据lgwr触发条件,事务提交执行lgwr,redo log buff写入redo log,事务从v$transaction中移除。
3清理块头,保存最后一个scn,事务插槽让别的事务正常使用,释放表头部的行锁(dbwn不是顺序写入,commit时并不马上释放块头的行锁,实际相应的dbwn完成才会释放。)
对dml执行rollback:
服务器进程根据数据文件块和buffer cache块的块头的事务列表和scn以及回滚段地址找到前映像来还原相应的数据块。
如果在一个事务中执行多个dml语句,产生了多个前映像,此时rollback,通过查找数据块头查找回滚段地址,oracle只保留了最早的前映像。
Commit完成了instance crash
由于事务提交lgwr已经完成了所有事务的redo log,即使buffer cache没有写入磁盘,重启实例后smon会根据redo log前滚数据文件到事务commit结束时。
Commit完成中途,instance crash:
1 Datafile和logfile同步
如果dml执行很长时间也没有commit,此时log buffer和buffer cache已经写入到磁盘,只是没有commit来标志事务的结束和把回滚段中前映像的标记为已提交,此时smon回滚数据文件和日志文件最后一次事务提交时。
2 logfile中redo log新于datafile中,两者不同步
此时logfile比datafile写入的事务的信息更多,本来也应该如此,dbwn发生前会优先发生lgwr,此时smon会优先把datafile前滚到logfile一致,然后回滚logfile和datafile到最后一次事务提交时。
就先整理这些吧,有些细节方面还需要后面更进一步的推敲。
精看细看文档,结合动手 思考练习,oracle就是沙漠和绿地不停的交互,不停的探讨中!
[@more@]