Buffer Cache 原理

摘要:
将数据块读入SGA后,它们的缓冲区被放置在挂起的哈希桶的链接列表(哈希链)中。此内存结构由大量子缓存缓冲区链锁存器保护。BufferCache概述BufferCache是SGA的一部分。Oracle使用BufferCache来管理数据块。BufferCache的最终目的是最小化磁盘I/O。BufferCache中有三种主要结构用于管理BufferCache。HashBucket和HashChainListOracle在内部Hash算法操作后将buffercache中的所有缓冲区放入不同的HashBucket中。每个HashBucket都有一个HashChainList,通过它连接bucket中的块。
在将数据块读入到SGA中,他们的缓冲区被放置在悬挂散列存储桶的链表中(散列链),这种内存结构由大量 子cache buffers chains锁存器(也称为散列锁存器或CBC锁存器)保护。


Buffer Cache概述
Buffer Cache是SGA的一部分,Oracle利用Buffer Cache来管理data block,Buffer Cache的最终目的就是尽可能的减少磁盘I/O。Buffer Cache中主要有3大结构用来管理Buffer Cache。


Hash Bucket与Hash Chain List
Oracle将buffer cache中所有的buffer通过一个内部的Hash算法运算之后,将这些buffer放到不同的 Hash Bucket中。每一个Hash Bucket中都有一个
Hash Chain List,通过这个list,将这个Bucket中的block串联起来。




下面举个简单的例子来介绍一下Hash 算法,Oracle的Hash 算法肯定没这么简单,具体算法只有Oracle公司知道。
•      一个简单的mod函数 ,我们去mod 4
Ø  1 mod 4 = 1
Ø  2 mod 4 = 2
Ø  3 mod 4 = 3
Ø  4 mod 4 = 0
Ø  5 mod 4 = 1
Ø  6 mod 4 = 2
Ø  7 mod 4 = 3
Ø  8 mod 4 = 0
……………省略…………………..
那么这里就相当于创建了4个Hash Bucket
如果有如下block:
blcok :DBA(1,1)  ------> (1+1) mod 4 =2  
block :DBA(1,2)  ------> (1+2) mod 4 =3
block :DBA(1,3)  ------> (1+3) mod 4 =0
block :DBA(1,4)  ------> (1+4) mod 4 =1
block :DBA(1,5)  ------> (1+5) mod 5 =2
………........省略…………………....
 
比如我要访问block(1,5),那么我对它进行Hash运算,然后到Hash Bucket为2的这个Bucket里面去寻找,Hash Bucket 为2的这个Bucket 现在有2个block,
这2个block是挂在Hash Chain List上面的




希望在散列链上添加,删除,搜索,检索,读取,或修改块的进程首先获得cache buffers chains latch,从而保护链上的缓冲区。


这样做可以保证独占的访问,并防止其他进程接下来读取或改变同一个链。为了完整性因此牺牲了并发性。

Buffer Cache 原理第1张

从图中我们可以看到,一个latch:cache buffers chains(x$bh.hladdr) 可以保护多个Hash Bucket,也就是说,如果我要访问某个block,我首先要获得这个latch,

一个Hash Bucket对应一个Hash Chain List,


而这个Hash Chain List挂载了一个或者多个Buffer Header。


Hash Bucket的数量受隐含参数_db_block_hash_buckets的影响,


Latch:cache buffers chains的数量受隐含参数_db_block_hash_latches的影响


Hash Bucket的数量受隐含参数_db_block_hash_buckets的影响,
Latch:cache buffers chains的数量受隐含参数_db_block_hash_latches的影响




SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  FROM x$ksppi x, x$ksppcv y
 WHERE x.inst_id = USERENV('Instance')
   AND y.inst_id = USERENV('Instance')
   AND x.indx = y.indx
   AND x.ksppinm LIKE '%_db_block_hash%'  2    3    4    5    6  ;


NAME      VALUE DESCRIB
------------------------------ ---------- ------------------------------
_db_block_hash_buckets      16384 Number of database block hash  buckets


_db_block_hash_latches      1024 Number of database block hash  Latches


可以用下面查询计算cache buffers chains latch的数量:
SQL> select count(*) from v$latch_children a,v$latchname b where a.latch#=b.latch# and b.name='cache buffers chains';


  COUNT(*)
----------
      1024


根据我们的查询,那么一个cache buffers chains latch 平均下来要管理
Select 16384/1024 from dual 16个块,那么现在我们随意的找一个latch,来验证一下前面提到的结构图。


SQL> select * from (select hladdr,count(*) from x$bh  group by hladdr) where rownum<=5;


HLADDR  COUNT(*)
-------- ----------
2D32792C 3
2D3279A8 4
2D327A24 4
2D327AA0 6
2D327D1C 3
我们查询latch address 为2D327AA0 所保护的data block


SQL> select hladdr,obj,dbarfil,dbablk, nxt_hash,prv_hash from x$bh where hladdr='2D327AA0' order by obj;


HLADDROBJ    DBARFIL  DBABLK NXT_HASH PRV_HASH
-------- ---------- ---------- ---------- -------- --------
2D327AA0 2     1   72670 2D327CFC 2D327CFC
2D327AA0       5841    1   11705 2D327D14 2D327D14
2D327AA0       6470    2    5969 2D327CEC 2D327CEC
2D327AA0      75313    2   58025 2D327CBC 2D327CBC
2D327AA0      75313    2   58258 2D327CDC 2D327CDC
2D327AA0      75347    2   66701 2D327CB4 2D327CB4


已选择6行。


请观察DBA(1,72670),它的NXT_HASH与PRV_HASH相同,也就是说DBA(1,72670)挂载在只包含有1个data block的 Hash Chain上。




当一个用户进程想要访问Block(1,72670):
l  对该Block运用Hash算法,得到Hash值。


l  获得cache buffers chains latch


l  到相应的Hash Bucket中搜寻相应Buffer Header


l  如果找到相应的Buffer Header,然后判断该Buffer的状态,看是否需要构造CR Block,或者Buffer处于pin的状态,最后读取。


l  如果找不到,就从磁盘读入到Buffer Cache中。


在Oracle9i以前,如果其它用户进程已经获得了这个latch,那么新的进程就必须等待,直到该用户进程搜索完毕(搜索完毕之后就会释放该latch)。从Oracle9i开始 cache 
buffers chains latch可以只读共享,也就是说用户进程A以只读(select)的方式访问Block(84,615093),这个时候获得了该latch,同时用户进程B也以只读的方式访问Block
(765,1259399),那么这个时候由于是只读的访问,用户进程B也可以获得该latch。但是,如果用户进程B要以独占的方式访问Block(765,1259399),那么用户进程B就会等待用户进
程A释放该latch,这个时候Oracle就会对用户进程B标记一个latch:cache buffers chains的等待事件。


我们遇到了latch:cache buffers chains该怎么办?


l  不够优化的SQL。大量逻辑读的SQL语句就有可能产生非常严重的latch:cache buffers chains等待,因为每次要访问一个block,就需要获得该latch,由于有大量的逻辑读,那
么就增加了latch:cache buffers chains争用的机率


2.Hash Bucket太少,需要更改_db_block_hash_buckets隐含参数。其实在Oracle9i之后,我们基本上不会遇到这个问题了,除非遇到Bug。所以这个是不推荐的,记住,在对


Oracle的隐含参数做修改之前一定要咨询Oracle Support。

<span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space: normal;">
</span></span>

免责声明:文章转载自《Buffer Cache 原理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Newtonsoft.Json 的基本用法TR2021_0000偶发数据库连接异常问题排查下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

哈希表(hash)

散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。 (来自维基百科) 其中前边说到的离散化也是一种特殊的哈希方式,只不过离散化注重保序性,因此使用二分查找...

Python基础:映射(字典)

一、概述 映射类型(Mapping Types)是一种关联式的容器类型,它存储了对象与对象之间的映射关系。 字典(dict)是Python中唯一的映射类型,它是存储了一个个 键值对(由 键 映射到 值)的关联容器。其中,键(key)必须是可哈希的Python对象,而 值(value)可以是任何Python对象。在功能上,Python中的字典类似于C++中...

php集成动态口令认证

这篇文章主要为大家详细介绍了php集成动态口令认证,动态口令采用一次一密、用过密码作废的方式来提高安全性能,感兴趣的小伙伴们可以参考一下 大多数系统目前均使用的静态密码进行身份认证登录,但由于静态密码容易被窃取,其安全性无法满足安全要求。 动态口令采用一次一密、用过密码作废的方式防止了密码被窃取带来的安全问题。动态口令分为HOTP(基于事件计数的动态口令,...

Android Verified Boot 2.0 AVB详解(基于Android P)

原文地址:https://android.googlesource.com/platform/external/avb/+/master/ 译文地址:https://blog.csdn.net/shangyexin/article/details/86649504 背景 在烧录系统镜像到设备的时候,发现烧写以后设备无限重启。请教了同事以后,发现需要输入下列...

集合与多线程面试

 集合 Java中集合和数组的区别? 一、集合和数组的区别区别1:数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值。 集合只能存储引用数据类型(对象)。集合也能存储基本数据类型(有点矛盾,看后句),但是在存储的时候会自动装箱变成对象。 区别2:数组长度是固定的,不能自动增长。 集合的长度是可变的,可以根...

unordered_map的哈希HASH重载——举例unordered_map与pair联合使用

有些时候,为了图省力,我们没准会这样的调用一个函数 unordered_map< pair<int, int>, int > mp; 但是很显然的是,这样的写法是会报错的,因为pair还没有HASH键值。 error: call to implicitly-deleted default constructor of 'std::...