何剑敏
Oracle ACS 华南区售后团队,首席技术工程师。多年从事第一线的数据库运维工作,有丰富项目经验、维护经验和调优经验,专注于数据库的整体运维。
_db_block_max_cr_dba 这个隐含参数的作用是控制每个block(即一个dba下,或者说x$bh.dbablk)的最多cr块的个数。默认值是6(5个CR+1个XCUR)。
当产生一致性读(CR)的时候,session会从前镜像读取块,加载到buffer cache中,加载的这个块,我们叫CR copy。保留多个版本的CR,可以缓解对buffer中block的并发争用(buffer busy wait),避免多个session同时读取一个buffer block。但是如果版本过多,挂在一个hash chain下的block太多,又会造成CBC latch的争用。所以oracle选择了6个版本。我们来测试一下CR copy的特性(数据库版本11.2.0.4)
数据初始化
检查初始情况
刚刚启动的时候,我们发现file#=4,block#=1365没有在buffer中。
开始构造一致性读:
session 1
session 2
当开始DML之后,block中数据文件中加载到buffer中,此时一定会有一个xcur的block,和cr block。这是因为DML is always performed on the current copy of the block (Status=xcur).
xcur的block表示当前已经被修改过的block,是最新的block,注意DI列(Dirty列)已经是Y,表示这个block是buffer中的脏块。cr block是在update之前,在内存中copy原来的xcur的block。我们看cr block的CR_SCN_BASE是update前一瞬间的SCN,即2687527。
即当update发生的时候,
(1)如果块在buffer中(块的状态为xcur),那么copy一份这个在buffer中的xcur的块,copy出来的块是cr块。更新这个块,且这个块的标记还是xcur。
(2)如果在buffer中没有这个块,那么将这个block从磁盘读到buffer中(此时状态为xcur。这个过程,类似进行了一次没有一致性读的select,select的时候,当前块状态也是为xcur),将buffer中的xcur块,做一份copy,copy出来的块成为cr块,更新这个块,且这个块的状态还是xcur
由于刚刚进行了update,且没有commit。所以现在的select是需要进行一致性读。
session 3:
SQL> select * from t1 where c1=1;
session 2:
第一次的select,oracle一次性创建了2个CR block,分别是在SCN 2687545和SCN 2687546的时候。这个时候,由于是需要一致性读,因此这次的select是从前镜像读取,从undo中读取,所以,也可以看到这个前镜像块是从undo的那个块上读取,可以看到有UBA(undo block address)的file id,block id和sequence。file id为3,是在undo tablespace上。
session 4:
SQL> select * from t1 where c1=1;
session 2:
第二次的select,oracle只创建了1个CR block,分别是在SCN 2687575的时候。 读取的是在undo上的同一个UBA file id,block id和sequence,所以,在undo文件上的块是同一个块,但是在buffer中,cr块目前已经有3个cr块了。另外还有一个cr块,但是这个块是在做update的时候,对于该session来说在update之前的xcur的copy。不是从undo文件中读取的block。
session 5:
SQL> select * from t1 where c1=1;
session 2:
第三次的select,oracle只创建了1个CR block,分别是在SCN 2687595的时候。 读取的是在undo上的同一个UBA file id,block id和sequence,所以,在undo文件上的块是同一个块,但是在buffer中,cr块目前已经有4个cr块了。
另外我们注意到,oracle已经把第一次做update的时候,SCN 2687527的cr块刷出去了。这个被丢弃的CR block,对我做update的session来说,已经没有用处,因为当前session的block的值已经更新,当前session所需要的block是xcur的那个block。而对已其他session来说,由于还没有commit,需要读取前镜像,可以直接做第一次和第二次cr block的copy;或者直接从undo中加载。
session 6:
SQL> select * from t1 where c1=1;
session 2:
第四次的select,oracle只创建了1个CR block,分别是在SCN 2687615的时候。 读取的是在undo上的同一个UBA file id,block id和sequence,所以,在undo文件上的块是同一个块,但是在buffer中,cr块目前已经有5个cr块了。
session 7:
SQL> select * from t1 where c1=1;
session 2:
第五次的select,oracle只创建了1个CR block,分别是在SCN 2687643的时候。 创建这个CR block的时候,把当前cr block列表中最早的SCN 2687545的block丢弃了。只保留5个CR block。
至此,我们看到,不同的session的select,对cr block的影响:
update但不commit,在update时产生一个cr block。
第一次select从undo获得前镜像产生2个cr block,当前共3个cr block
第二次select再产生一个cr block,当前共4个cr block
第三次select再产生一个cr block,且丢弃update时的cr block,当前共4个cr block
第四次select再生产一个cr block,至此已经有了5个cr block和1个xcur block
第五次select再产生一个cr block,丢弃第一次select产生的第一个block,只保留5个cr block和1一个xcur block
再后续select的话,每产生一个cr block,丢弃最早的cr block
我们再来看看flush buffer cache的影响:
session 2:
session 8:
SQL> select * from t1 where c1=1;
session 2:
我们看到,flush buffer cache之后,xcur的block,即标记为dirty的block也被刷出buffer cache,所有的buffer block都是显示free。
但进行第一次select的时候,被修改的xcur block,还是从db file加载到内存,且被记录成dirty的block。另外,select出来的前镜像,也从undo加载到内存,形成第一个cr block。
到了这个,顺便问个问题,现在都流行database in memory,如果我的内存是256G的,能放得下256G的database吗?读了上面的问题,相信你已经有了初步的答案。:)
---the end
如何加入"云和恩墨大讲堂"微信群
搜索 盖国强(Eygle) :eyygle,或者扫描下面二维码,备注:云和恩墨大讲堂,即可入群。每周与千人共享免费技术分享,与讲师在线讨论。
(OraNews)回复关键字获取
2016DTCC, 2016数据库大会PPT;
DBALife,"DBA的一天"精品海报大图;
12cArch,“Oracle 12c体系结构”精品海报;
DBA01,《Oracle DBA手记》第一本下载;
YunHe,“云和恩墨大讲堂”案例文档下载;