1.为什么要使用buffer cache???
buffer cache就是一块含有许多数据块的内存区域,这些数据块主要都是数据文件里的数据块内容的拷贝。从buffer cache中读取一个数据块一般需要100ns左右,从一般的存储硬盘中读取一个数据块需要10ms;所以大概算一下,从内存中读取数据块比从硬盘中快近十万倍。
故oracle在读取数据块时,先在buffer cache中查找,如存在,则读取--逻辑读;如果数据块不存在,则发生物理读,从物理文件中将数据读入buffer cache(不考虑直接读的情况)。
在初始化参数中,设置buffer cache大小的参数是db_cache_size
在11.2.0.4.0中此参数支持动态修改:
BYS@ bys3>show parameter db_cache_size
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_cache_size big integer 48M
BYS@ bys3>alter system set db_cache_size=40M;
System altered.
BYS@ bys3>show parameter db_cache_size
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_cache_size big integer 40M
buffer cache所提供的功能主要包括:
1) 通过缓存数据块,从而减少I/O。2) 通过构造CR块,从而提供读一致性功能。
3) 通过提供各种lock、latch机制,从而提供多个进程并发访问同一个数据块的功能。
2.buffer cache的内存结构图解
话说大神们都用WORD画图,为了模仿大神, 我也用WORD画了好久的原创:
从这张buffer cache的内存结构图,用一句话来说明
buffer cache中 结构大致是:buffer pool--->working set--->hash latch--->hash bucket--->hash chain--->buffer header--->buffer dba
下面就把这些结构的概念大致说明一下: --更详细的的在之后
1.buffer header:
每一个数据块在被读入buffer cache时,都会先在buffer cache中构造一个buffer header,buffer header与数据块一一对应(buffer header 中有指定buffer 具体内存地址的信息)。buffer header包含的主要信息有: 详见:
1) 该数据块在buffer cache中实际的内存地址。
2) 该数据块的类型,包括data、segment header、undo header、undo block等等。
3) 该buffer header所在的hash chain,是通过在buffer header里保存指向前一个buffer header的指针和指向后一个buffer header的指针的方式实现的。
4) 该buffer header所在的LRU、LRUW、CKPTQ等链表(这些链表我们后面都会详细说明)。也是通过记录前后buffer header指针的方式实现。
5) 当前该buffer header所对应的数据块的状态以及标记。
6) 该buffer header被访问(touch)的次数。
7) 正在等待该buffer header的进程列表(waiter list)和正在使用该buffer header的进程列表(user list)。
我的测试环境:buffer cache大小是40M,buffer的个数是4936(每个buffer在x$bh中都存在一条记录)。 在11G中db_cache_size 是一个动态参数,可以手动更改此参数后再查询x$bh,可以发现buffer的个数也会随之变化的。
SYS@ bys3>show parameter db_cache_si
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_cache_size big integer 40M
SYS@ bys3>select count(*) from x$bh; --用这句查出buffer的个数,也就是可以存放4936个数据块(因为还有一部分空间是生成buffer header),db_cache_size/4936-8K就能算出一个buffer header的大致大小
COUNT(*)
----------
4936
################################
2.hash chain与hash bucket:
从上图中可以看到,一个hash bucket是对应着一条hash chain的。Hash Bucket-直译叫hash桶Hash Bucket 一个逻辑上的概念,通过对buffer header 里记录的数据块地址和数据块类型运用hash算法以后,得到的组号。
hash chain 将属于同一个hash bucket的所有buffer header串起来的链表
服务器进程将数据块读取到buffer cache后,将数据块的DBA进行HASH运算,将具有相同HASH值的数据块的buffer header挂载到同一个hash bucket下(可能多个块的HASH值相同),并用hash chain串联起来。
buffer cache中,缺省的hash bucket的数量或者说缺省有多少条hash chain链表,是由一个隐藏参数: _db_block_hash_buckets决定的。
关于_db_block_hash_buckets参数的取值:据说在8i下,该参数缺省为db_block_buffers×2;但是到了9i以后,该参数似乎取的是小于且最接近于db_block_buffers×2的素数。
在ORACLE 10G和11G中,默认值是大于2倍的buffer数量的最小的2的幂的值。举例如buffer数量是500,2倍就是1000,那么大于1000的最小的2的幂的值是1024,也就是就会有1024个hash bucket。
在我测试系统中:buffer 数量是4936,2倍是9872,从隐含参数_db_block_hash_buckets 查出bufket数量是16384 ,完全符合。
SYS@ bys3>select count(*) from x$bh; --用这句查出buffer的个数
COUNT(*)
----------
4936
P_NAME P_DESCRIPTION P_VALUE ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ ---
