buffer cache实验9-从buffer caceh中读取数据块解析-从逻辑读到物理读

发布时间:2016-12-9 0:22:21 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"buffer cache实验9-从buffer caceh中读取数据块解析-从逻辑读到物理读",主要涉及到buffer cache实验9-从buffer caceh中读取数据块解析-从逻辑读到物理读方面的内容,对于buffer cache实验9-从buffer caceh中读取数据块解析-从逻辑读到物理读感兴趣的同学可以参考一下。

先来张大图:   所用SQL语句: BYS@ ocm1>select dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block#,deptno from bys.test;      FILE#     BLOCK#     DEPTNO ---------- ---------- ----------          4        391         10 就以上图为例,文字描述分析一下前台进程发出查询语句时获取所需数据块的过程: 注:本文不涉及SQL语句的解析部分、客户端与服务器交互等,只涉及buffer cache。 这里的物理读是非直接路径读、非大表全表扫描--此点最后会有介绍。 如果发出的是更新语句,只是在buffer pin上所加的锁为X独占锁,其它步骤基本一致。 本文的例子只读取了一个数据块。 从buffer cache中读取一个数据块一般需要100ns左右,从一般的存储硬盘中读取一个数据块需要10ms;所以大概算一下,从内存中读取数据块比从硬盘中快近十万倍。 故oracle在读取数据块时,先在buffer cache中查找,如存在,则读取--逻辑读;如果数据块不存在,则发生物理读,从物理文件中将数据读入buffer cache(不考虑直接读的情况)。 之前写过的逻辑读的: 数据读取之逻辑读简单解析--关于BUFFER CACHE 下面正式开始:--首先是逻辑读的过程 1.前台进程发出查询语句select deptno from bys.test; 2.根据DBA计算HASH值,根据HASH值找到相应的Hash bucket 3.获取CBC LATCH,如获取失败,则将产生:latch:cache buffers chains 4.在CBC LATCH保护下,服务器进程扫描hash chain,查找是否有所需BH 5.如查找到所需BH,将在Buffer Header上加buffer pin锁(这里是读操作所以是共享锁(找到BH时的锁常见有:当前读锁、一致读锁或修改锁),如获取buffer pin失败(比如正在X模式申请S模式),会产生buffer busy waits等待),并根据BH中指定的块在内存中实际地址,读取buffer,并将结果返回前台进程。读取完毕(纳秒级)后,将再次获取CBC LATCH,释放buffer pin锁,再释放CBC LATCH。  -----以上为逻辑读,如果未找到buffer,将发生如下的物理读: 6.如果未查找到所需BH,将发生物理读。服务器进程将从磁盘上的相应数据文件中读取所需块,并将此块读入buffer cche中。 7.将块读入buffer cache中时,如何找到一个可以使用的buffer呢?下面步骤进行一步步解析。 8.首先在辅助LRU的最尾端向前查找可用buffer,TCH<2的块可以被重用。 9.如果辅助LRU最尾端的块是TCH<2的块,则将直接使用此块,并将其移动到主LRU的冷端头。 同时也会根据此块的DBA进行HASH,查找相应的HASH BUCKET,将此块加入到对应的HASH CHAIN上,并对BH中的相应信息进行修改(如对应X$BH中的LRU_FLAG,NXT_HASH、BA等字段的具体值)--此过程也需要相应的CBC LATCH /buffer pin锁的获取释放等。 再把数据块的值返回前台进程,此时物理读就完成了。 10.如果辅助LRU最尾端的块是TCH>=2的块,则首先将此块移动到主LRU的热端头,同时TCH清零;然后在在辅助LRU上继续向前查找,直到找到可用的块---TCH<2。之后的过程和步骤9中的就一样了。(SMON每三秒时,服务器进程扫描空闲BUFFER时;都会把辅助LRU中TCH大于等于2的移到主的热端头) 11.如果在辅助LRU上搜索完毕扔未找到可以使用的块,则将从主LRU的冷端尾开始搜索。 12.如果主LRU最尾端的块是TCH<2的块,则将直接使用此块,并将其移动到主LRU的冷端头,TCH为1。如是TCH>=2的块,则将其移动到热端头,TCH清零。如果是脏块,则将其移动到主LRUW上。依此规则向前搜索查找可用块。(SMON每3秒,从主LRU冷端查找TCH小于2的非脏块到辅助LRU确保辅助LRU中有可用BUFFER) 13.如果从主LRU最尾端向前搜索了40%(隐含参数_db_block_max_scan_pct,)还未找到可用块,则将触发DBWR写LRUW上的脏块--(CKPTQ队列的写不涉及LRUW,只有DBWR会写LRUW上脏块,并且写的是LRUW上的全部脏块-每三秒醒来也要全部写出LRUM上所有块才会休眠。写LRUW上脏块的步骤是:DBWR进程写时或者SMON进程每三秒醒来时(LRUW进程不像辅助LRUW那样,非DBWR进程也允许访问),会将主LRUW上的一部分脏块移动到辅助LRUW,然后在辅助LRUW上排序、写入磁盘;然后再从主LRUW上移动下一批,直到写出完毕再次进入睡眠。并且在DBWR写出过程中,会产生free buffer waits),写出后的buffer将重新挂载到辅助LRU上并变为可用。 关于大表全表扫描及_small_table_threshold   参数的说明: 大小表的界限是:_small_table_threshold,此参数中的VALUE 是数据块个数。 大表的全表扫描只使用辅助LRU,其块的TCH为1。这样做不对主LRU上的块进行冲击,同时也方便大表中块的重用。此时如有其它用户语句需要从辅助LRU上查找可用buffer,直接可以使用,节约时间。 小表的全表扫描和普通数据块一样来查找可用buffer. P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ ---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- ----- _small_table_threshold                   lower threshold level of table size for direct rea89                             TRUE      FALSE    FALSE                                          ds 这里的89是BLOCK数量,表所使用的BLOCK的数量--不是直接的MB或者KB。。 _small_table_threshold的值在数据库启动的时候自动配置成BUFFER数量的2%。--可以修改buffer cache大小并重启数据库验证。 SYS@ bys3>select count(*)*0.02 from x$bh;   ---从X$BH中获取BUFFER的数量 COUNT(*)*0.02 -------------         88.98 关于直接路径读的说明: ---来自百度 直接路径读(direct path read)通常发生在Oracle直接读数据到进程PGA时,这个读取不需要经过SGA。直接路径读等待事件的3个参数分别是file number(指绝对文件号)、first dba、block cnt数量。在Oracle 10g/11g中,这个等待事件被归于User I/O一类。db file sequential read、db file scattered read、direct path read 是常见的集中数据读方式。 在数据仓库环境大量的direct path read是正常的。在OLTP中,大量direct path read意味应用有问题导致大量磁盘排序读取操作。 最为常见的是第一种情况。在DSS系统中,存在大量的direct path read是很正常的,但是在OLTP系统中,通常显著的直接路径读(direct path read)都意味着系统应用存在问题,从而导致大量的磁盘排序读取操作。直接路径写(direct paht write)通常发生在Oracle直接从PGA写数据到数据文件或临时文件,这个写操作可以绕过SGA。直接路径写等待事件的3个参数分别是:file number(指绝对文件号)、first dba和block cnt数量,在Oracle 10g/11g中,这个等待事件同direct path read一样被归于User I/O一类。这类写入操作通常在以下情况被使用:·直接路径加载;·并行DML操作;·磁盘排序;·对未缓存的“LOB”段的写入,随后会记录为direct path write(lob)等待。最为常见的直接路径写,多数因为磁盘排序导致。对于这一写入等待,我们应该找到I/O操作最为频繁的数据文件(如果有过多的排序操作,很有可能就是临时文件),分散负载,加快其写入操作。 直接路径插入时,不产生表块的回滚信息,而是依赖高水位点实现回滚 但是,如果表有索引,将会产生索引的回滚信息,而且索引的块会被读进buffer cache Oracle官方文档建议,如果使用直接路径插入,向表中传送大量数据,可先将表上的索引删掉,插入结束后,再重新建立索引 在Oracle 11g版本中串行的全表扫描可能使用直接路径读取(direct path read)的方式取代之前版本中一直使用的DB FILE SCATTERED READ, 显然direct path read具备更多的优势: 1. 减少了对latch争用 2.物理IO的大小不再取决于buffer_cache中所存在的块; 试想某个8个块的extent中1,3,5,7号块在高速缓存中,而2,4,6,8块没有被缓存,传统的方式在读取该extent时将会是对2,4,6,8块进行4次db file sequential read,其效率往往要比单次读取这个区间的所有8个块还要低得多, 而direct path read则可以完全避免这类问题,尽可能地单次读入更多的物理块。 当然直接路径读取也会引入一些缺点: 1.在直接路径读取某段前需要对该对象进行一次段级的检查点(A segment checkpoint). 2.可能导致重复的延迟块清除操作 http://www.oracledatabase12g.com/archives/direct-read-impact-on-delayed-block-read.html

上一篇:ExtJs中继承的实现与理解—extend
下一篇:CentOS下yum安装LAMP

相关文章

相关评论