千家信息网

Commit和dbwr没有任何关系、物理读产生逻辑读、快照过旧的理解

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,The COMMIT statement ends the current transaction, making its changes permanent and visible to other
千家信息网最后更新 2025年02月01日Commit和dbwr没有任何关系、物理读产生逻辑读、快照过旧的理解The COMMIT statement ends the current transaction, making its changes permanent and visible to other users.

commit仅仅是触发lgwr把日志缓冲数据写入在线重做日志并且把提交了数据的事务的scn将记录在控制文件中,注意此时的数据文件中的scn没有变化,COMMIT不会触发任何的checkpoint

The DBWn process writes dirty buffers to disk under the following conditions:
--When a server process cannot find a clean reusable buffer after scanning a threshold number of buffers, it signals DBWn to write. DBWn writes dirty buffers to disk asynchronously if possible while performing other processing.
--DBWn periodically writes buffers to advance the checkpoint
在以下条件下,DBWn进程将脏缓冲区写入磁盘:
--当服务器进程在扫描阈值数量的缓冲区之后找不到干净的可重用缓冲区时,它会将DBWn发信号写入。 执行其他处理时,如果可能,DBWn将异步缓冲区写入磁盘。
--定期写入缓冲区以推进检查点

所以Commit和Dbwr没有任何关系
一些数据块,产生它们的事务还未提交,但是它们已经被DBWn写回到数据文件中了,当然也提前写入redo中了(dbwr写前协议,即某个数据还没有写入redo就要发生dbwr则必须等待lgwr将数据写入redo,写redo不止包含commit一种条件。)DBWn清理脏数据块从来就同事务commit与否没有任何关系。只要内存没有有空闲,就会把这些脏块给flush到数据文件内。这些未提交的事务但被写入数据文件的数据,即便是已经在你的数据文件了。事务恢复阶段将按需把这些数据回滚掉事务恢复后已经是垃圾数据了(当事务修改数据时,会先在回滚段中保存一份修改前数据和事务开始的SCN,如果事务没有commit,则标记段头部为ITL,如果commit,则把commit时刻的SCN写入数据块中,回滚的时候根据段是否commit来定位,如果没有commit就直接找到undo中这个会话最初的scn和前镜像直接回滚,不会一个个数据块去undo,否则10G都已经写入数据文件那回滚得多久啊)

实验过,10G容量级别的大量insert操作了30分钟,但是不commit,会发现redo log不停的切换产生归档日志,且datafile不停增加。再直接shutdown abort,startup的时候发现很快,不需要30分钟。前滚回滚过程应该是这样的:数据库记录了最新的SCN、增量checkpoint的SCN、redo log的最大SCN,通过增量checkpoint的SCN开始应用redo log直到redo log的最大SCN乃至最新的SCN,这样就完成了前滚,在回滚的时候直接读取undo中这个会话最初的scn和前镜像直接回滚,不会一个个数据块去undo,否则10G都已经写入数据文件那回滚得多久啊





读取一个数据块,则这个数据块要么直接来自datafile,要么来自Buffer Cache,如果来自datafile,则也要读取到SGA中的Buffer Cache中,也就是一次物理读必然产生一个逻辑读的意思,数据块上都会有最后一次修改数据块后commit的SCN
如果一个事务需要修改数据块中数据,会先在回滚段中保存一份修改前数据和事务开始的SCN,然后再更新Buffer Cache中的数据块的数据,如果没有commit则标记段头部的TIL,如果已经commit则把commit后的SCN更新到数据块上。当其他进程读取数据块时,会先比较数据块上的SCN和自己的SCN。如果数据块上的SCN 小于等于进程本身的SCN,则直接读取数据块上的数据;如果数据块上的SCN大于进程本身的SCN,则会从回滚段中找出修改前的数据块读取数据。
Oracle的一致性读的理解:一个语句在读取数据快时,如果发现这个数据块是在它读取的过程中被修改的(数据块上的SCN 大于等于读取进程本身的SCN),就不直接从数据块上读取数据,而是从相应的undo中读取数据。这就保证了最终结果应该是读操作开始时的那一时刻的快照 (snapshot),而不会受到读期间其他事务的影响。当然如果放在undo里面的数据被覆盖了,就会报错ORA-01555:快照过旧


了解Oracle在什么情况下会产生ORA-01555:快照过旧错误
假设有一张6000万行数据的testdb表,预计testdb全表扫描1次需要2个小时,参考过程如下:
1、在1点钟,用户A发出了select * from testdb;此时不管将来testdb怎么变化,正确的结果应该是用户A会看到在1点钟这个时刻的内容。
2、在1点30分,用户B执行了update命令,更新了testdb表中的第4100万行的这条记录,这时,用户A的全表扫描还没有到达第4100万条。毫无疑问,这个时候,第4100万行的这条记录是被写入了回滚段,假设是回滚段UNDOTS1,如果用户A的全表扫描到达了第4100万行,是应该会正确的从回滚段UNDOTS1中读取出1点钟时刻的内容的。
3、这时,用户B将他刚才做的操作提交了,但是这时,系统仍然可以给用户A提供正确的数据,因为那第4100万行记录的内容仍然还在回滚段UNDOTS1里,系统可以根据SCN到回滚段里找到正确的数据,但要注意到,这时记录在UNDOTS1里的第4100万行记录已经发生了重大的改变:就是第4100万行在回滚段UNDOTS1里的数据有可能随时被覆盖掉,因为这条记录已经被提交了!
4、由于用户A的查询时间漫长,而业务在一直不断的进行,UNDOTS1回滚段在被多个不同的transaction使用着,这个回滚段里的extent循环到了第4100万行数据所在的extent,由于这条记录已经被标记提交了,所以这个extent是可以被其他transaction覆盖掉的!
5、到了1点45分,用户A的查询终于到了第4100万行,而这时已经出现了第4条说的情况,需要到回滚段UNDOTS1去找数据,但是已经被覆盖掉了,这时就出现了ORA-01555错误。
0