Buffer cache


一、概念引出

在数据文件(datafile)中,存放的是表,而数据文件本身是被分成大小相等的若干块,而每个块的大小一般为8k,也可以为2k,4k,16k,32k。

范例:查看当前数据库块的大小

SQL>show parameter block

 

NAME                                   TYPE           VALUE

--------------------------------       -----------  ------------

db_block_buffers                     integer         0

db_block_checking                    string          FALSE

db_block_checksum                    string          TRUE

db_block_size                        integer         8192

db_file_multiblock_read_count        integer         16

观察可知,当前块大小为8k。还有一点需要知道:ORACLE中I/O的最小单位就是ORACLE块。而与数据文件中“块”对应的就是buffercache中的“buffer”,即在磁盘上我们称为“块(block)”,而在内存中我们称为“buffer”。因为buffer的大小与块的大小相同,所以可以通过查找当前buffercache的大小和当前块的大小去推算出当前DB中共有几多个块。

范例:计算当前buffercache的总buffer数

SQL>show parameter db_cache_size

 

NAME                   TYPE           VALUE

------------------- ------------- ------------------

db_cache_size        biginteger   200M       -- buffer cache的大小

计算公式:db_cache_size/db_block_size = 200M / 8192k = 25600 个

所以,当前buffer cache中共有25600个buffer。

一般原则,数据文件中一个块存储多个行的,极少情况下多个块存储一行。Server process在读取块的,是把整个块读进buffer中,所以每个“块(block)”与每个“buffer”的大小是相等的。

据说还有一个可以计算整个数据库所有文件中block的总和:??但是结果与上面不同,是否是因为这个是计算整个数据库的,而上面的只是计算当前buffercache中存了多少个buffer

SQL>select sum(blocks) from dba_data_files;

 

SUM(BLOCKS)

-----------

     117760

 

二、buffer cache作用

(1)缓存datafile,从而减少I/O。

(2)构造CR([C]onsistent [R]ead)块。顾名思义,一致读即为了ORACLE在进行DML操作时,不阻塞SELECT操作。当select读取的行在另外会话被修改过而未被提交时,则会在buffer cache中根据UNDO的相关信息创建一个与被修改前一样的块供select读取,所以CR块同样在buffer中。

三、buffer cache的构造

1、CBC(cache bufferchain)

CBC链负责把共享同一个HASH值的BH(buffer header,用于存储buffer的地址)串起来。

我们通过SQL语句执行过程再来分析一下,客户端发出SQL语句,serverprocess拿到语句后,通过计算,分析该语句应该挂在buffer cache的什么位置,然后去CBC中遍历BH,如果找不到,再去硬盘(datafile)中把相应的块读到buffer里面,接下来就把这个buffer的地址信息(BH)再挂到CBC链。以上过程都由server process完成。

2、LRU、LRUW

将脏块写回磁盘的后台进程是DBWn,DBWn的主要任务是负责buffer cache中的脏块合理,及时地写回到磁盘。触发DBWn的发生有几点:

(1)每隔3秒(由“增量检查点”决定);

(2)当server process在buffer中寻找可用buffer(free或clean)时,但检索到了一定的程度还没有找到,此时也会触发DBWn把部分的脏块写回磁盘;

(3)数据库关闭时,DBWn会把脏块全部写回磁盘。

范例:设置DBWn的数量

SQL>show parameter writer

 

NAME                           TYPE       VALUE

--------------------------- --------   -----------------

db_writer_processes         integer        1

SQL>alter system set db_writer_processes = 2 scope=spfile;

 

Systemaltered.

 

SQL>startup force       -- 使用此语句重启DB十分危险,不建议在生产环境使用

ORACLEinstance started.

 

TotalSystem Global Area  578813952 bytes

FixedSize                  2022472 bytes

VariableSize             348128184 bytes

DatabaseBuffers          226492416 bytes

RedoBuffers                2170880 bytes

Database mounted.

Databaseopened.

SQL>show parameter writer

 

NAME                           TYPE       VALUE

--------------------------- --------   -----------------

db_writer_processes         integer        2

SQL> !ps-ef|grep oracle     -- 查看当前ORACLE进程

……

oracle   16799    1  0 10:22 ?        00:00:00 ora_mman_wolex

oracle   16801    1  0 10:22 ?        00:00:00 ora_dbw0_wolex

oracle   16803    1  0 10:22 ?        00:00:00 ora_dbw1_wolex

oracle   16805    1  0 10:22 ?        00:00:00 ora_lgwr_wolex

oracle   16807    1  0 10:22 ?        00:00:00 ora_ckpt_wolex

……

3、checkpointqueue(检查点队列)

四、buffer cache参数配置

在OLTP系统中,对于DB_CACHE_SIZE的设置,推荐配置是:

DB_CACHE_SIZE = SGA_MAX_SIZE/2SGA_MAX_SIZE*2/3

范例:查看buffercache的大小,并尝试调整。

SQL>select component,current_size,min_size from v$sga_dynamic_components;

 

COMPONENT                CURRENT_SIZE   MIN_SIZE

------------------------- ------------ ----------

shared pool                  289406976  285212672

large pool                     4194304    4194304

java pool                      4194304    4194304

streams pool                         0          0

DEFAULT buffer cache          12582912   12582912

KEEP buffer cache                    0          0

RECYCLE buffer cache                 0          0

DEFAULT 2K buffer cache              0          0

DEFAULT 4K buffer cache              0          0

DEFAULT 8K buffer cache              0          0

DEFAULT 16K buffer cache             0          0

DEFAULT 32K buffer cache             0          0

ASM Buffer Cache                     0          0

 

13 rows selected.

 

SQL> alter system set db_cache_size = 200M scope =both;

alter system set db_cache_size = 200M scope = both

*

ERROR at line 1:

ORA-32017: failure in updating SPFILE

ORA-00384: Insufficient memory to grow cache

以上的buffer cache大小是由SGA_TARGET默认设置的,一般来说buffer cache的值应该满足:DB_CACHE_SIZE =SGA_MAX_SIZE/2~ SGA_MAX_SIZE*2/3。因此可以看出shared_pool在这里设置的大小并不合理。

还有一个问题就是,我们现在并不能把buffer cache的大小调大,因为SGA_TARGET已经把内存分配给了各个池,没有足够内存去扩大buffer cache了。调大方法及步骤如下:

调大SGA_MAX_SIZE → 重启DB → 调大SGA_TARGET → 调大buffer cache

SQL>show parameter sga

 

NAME                                 TYPE           VALUE

------------------------------------ -----------    -----------

lock_sga                             boolean        FALSE

pre_page_sga                         boolean        FALSE

sga_max_size                         big integer    300M

sga_target                           big integer    300M

 

SQL>alter system set sga_max_size = 500M scope = spfile;

 

System altered.

 

SQL>startup force

ORACLE instance started.

 

Total System Global Area 524288000 bytes

Fixed Size                  2022080 bytes

Variable Size            503317824 bytes

Database Buffers           16777216 bytes

Redo Buffers                2170880 bytes

Database mounted.

Database opened.

SQL>alter system set sga_target = 500M scope = both;

 

System altered.

 

SQL>show parameter sga

 

NAME                                 TYPE           VALUE

------------------------------------ -----------    -----------

lock_sga                             boolean        FALSE

pre_page_sga                         boolean        FALSE

sga_max_size                         big integer    500M

sga_target                           big integer    500M

 

SQL>alter system set db_cache_size = 200M scope = both ;

 

System altered.

 

SQL>select component,current_size,min_size from v$sga_dynamic_components;

 

COMPONENT                CURRENT_SIZE   MIN_SIZE

------------------------- ------------ ----------

shared pool                  285212672  285212672

large pool                     4194304    4194304

java pool                      4194304    4194304

streams pool                         0          0

DEFAULT buffer cache         226492416   12582912

KEEP buffer cache                    0          0

RECYCLE buffer cache                 0          0

DEFAULT 2K buffer cache              0          0

DEFAULT 4K buffer cache              0          0

DEFAULT 8K buffer cache              0          0

DEFAULT 16K buffer cache             0          0

DEFAULT 32K buffer cache             0          0

ASM Buffer Cache                     0          0

 

13 rows selected.

 

范例:通过分析判断buffer cache该设置多大

SQL> setlinesize 100

SQL> setpagesize 40

SQL>   select size_for_estimate"Cache Size (MB)",

            size_factor,

        buffers_for_estimate"Buffers",

        estd_physical_read_factorest_read_factor,

        estd_physical_readsest_phy_red,

        estd_physical_read_timeest_phy_red_t

from       v$db_cache_advice

where  name = 'DEFAULT'

and block_size=(  select value

                    from v$parameter

                    where

                   name='db_block_size');

 

Cache Size(MB) SIZE_FACTOR    BuffersEST_READ_FACTOR EST_PHY_RED EST_PHY_RED_T

-------------------------- ---------- --------------- ----------- -------------

             20       .0926       2475          1.0898        2538             0

             40       .1852       4950               1        2329             0

             60       .2778       7425               1        2329             0

             80       .3704       9900               1        2329             0

            100        .463      12375               1        2329             0

            120      .5556      14850               1        2329             0

            140       .6481      17325               1        2329             0

            160       .7407      19800               1        2329             0

            180       .8333     22275               1        2329             0

            200       .9259      24750               1        2329             0

            216           1      26730               1        2329             0

            220      1.0185      27225               1        2329             0

            240      1.1111      29700               1        2329             0

            260      1.2037      32175               1        2329             0

            280      1.2963      34650               1       2329             0

            300      1.3889      37125               1        2329             0

            320      1.4815      39600               1        2329             0

            340      1.5741      42075               1        2329             0

            360      1.6667      44550               1        2329             0

            380      1.7593      47025               1        2329             0

            400      1.8519      49500               1        2329             0

 

21 rowsselected.

buffer状态

● x$bh视图

从x$bh视图中可以发现有一列state,表示的就是buffer状态,每个数字的含义如下:

0:free,no valid block image

1:xcur,a current mode block,exclusive to thisinstance

2:scur,a current mode block,shared with other instance

3:cr,a consistent read (stale) block image

4:read,buffer is reserved for a block being read from disk

5:mrec,a block in media recovery mode

6:irec,a block in instance (crash) recovery mode

xcur块指的是从磁盘中读入到buffer cache中的块;当会话A对一个xcur块进行修改后而没有提交,此xcur块即成为了脏块,而此时如果会话B需要对此xcur块进行读操作,但由于会话A未进行提交,所以会话B无法访问此xcur块,所以ORACLE会根据UNDO中的记录值在buffer cache中创建一个cr块,此cr块对应与会话B要访问的xcur块,但此cr块记录的是它对应的xcur块被修改前的值。

下面做一系列实验,查看块当前的各种状态

SQL> startup force

ORACLEinstance started.

 

Total SystemGlobal Area  524288000 bytes

FixedSize                  2022080 bytes

VariableSize             293602624 bytes

DatabaseBuffers          226492416 bytes

RedoBuffers                2170880 bytes

Databasemounted.

Databaseopened.

SQL> select     o.object_name,

 2    decode(state,0,'free',1,'xcur',2,'scur',3,'cr',4,'read',5,'mrec',

 3     6,'irec',7,'write',8,'pi')state,

 4     count(*) blocks

 5  from       x$bh b,dba_objects o

 6  where      b.obj = o.data_object_id

 7  and        o.object_name = 'T1'

 8  group by o.object_name,state

 9  order by blocks desc;

 

no rowsselected        -- DB开始一启动的时候,buffer cache并没有T1的记录

 

SQL> select * from t1;

 

        ID NAME

------------------------------

         1 wolex

         2 alex

         3 john

 

SQL> select     o.object_name,

decode(state,0,'free',1,'xcur',2,'scur',3,'cr',4,'read',5,'mrec',

6,'irec',7,'write',8,'pi') state,

count(*) blocks

from       x$bh b,dba_objects o

where      b.obj = o.data_object_id

and        o.object_name = 'T1'

group by o.object_name,state

order by blocks desc;

 

OBJECT_NAME          STATE                                BLOCKS

---------------------------------------------------- ----------

T1                   xcur                                      2

T1                   cr                                        1

通过观察可以发现DB启动后,第一次对T1表进行查询操作时,也会有cr块产生,个人估计原因可能是第一次查询buffer cache里面还没有缓存?但之后的同一会话中查询操作并不会产生cr块,继续看实验:

SQL> alter system flushbuffer_cache;

                    -- 此语句会清空buffercache,实际生产环境中应谨慎使用

Systemaltered.

 

SQL> select     o.object_name,

 2    decode(state,0,'free',1,'xcur',2,'scur',3,'cr',4,'read',5,'mrec',

 3     6,'irec',7,'write',8,'pi')state,

 4     count(*) blocks

 5  from       x$bh b,dba_objects o

 6  where      b.obj = o.data_object_id

 7  and        o.object_name = 'T1'

 8  group by o.object_name,state

 9  order by blocks desc;

 

OBJECT_NAME          STATE                                BLOCKS

---------------------------------------------------- ----------

T1                   free                                      2

 

SQL> select * from t1;

 

        ID NAME

------------------------------

         1 wolex

         2 alex

         3 john

 

SQL> select     o.object_name,

 2    decode(state,0,'free',1,'xcur',2,'scur',3,'cr',4,'read',5,'mrec',

 3     6,'irec',7,'write',8,'pi')state,

 4     count(*) blocks

 5  from       x$bh b,dba_objects o

 6  where      b.obj = o.data_object_id

 7  and        o.object_name = 'T1'

 8  group by o.object_name,state

 9  order by blocks desc;

 

OBJECT_NAME          STATE                                BLOCKS

---------------------------------------------------- ----------

T1                   xcur                                      2

T1                   free                                      2

我们发现即使是清空了buffer cache,但还是有free块,为什么呢?应该是buffer cache中的buffer被清空了,但是CBC并没有被清空,链上挂的地址内容依然指向到buffer里面(即使状态为free)。

接着上面的实验往下做,向T1表中插入一条数据,但不commit,然后再开一个会话进行查询操作:

SQL> insert into t1values(4,'smith');

 

1 row created.

 

SQL> select     o.object_name,

 2    decode(state,0,'free',1,'xcur',2,'scur',3,'cr',4,'read',5,'mrec',

 3     6,'irec',7,'write',8,'pi')state,

 4     count(*) blocks

 5  from       x$bh b,dba_objects o

 6  where      b.obj = o.data_object_id

 7  and        o.object_name = 'T1'

 8  group by o.object_name,state

 9  order by blocks desc;

 

OBJECT_NAME          STATE                                BLOCKS

---------------------------------------------------- ----------

T1                   xcur                                      2

T1                   free                                      2

 

可以发现在当前会话中并没有cr块产生,所以再另外开一个会话,进行查询操作:

Session_02 > select * from t1;

 

        ID NAME

------------------------------

         1 wolex

         2 alex

         3 john

         4 smith

回到刚才的会话,查看块状态:

SQL> select     o.object_name,

 2    decode(state,0,'free',1,'xcur',2,'scur',3,'cr',4,'read',5,'mrec',

 3     6,'irec',7,'write',8,'pi')state,

 4     count(*) blocks

 5  from       x$bh b,dba_objects o

 6  where      b.obj = o.data_object_id

 7  and        o.object_name = 'T1'

 8  group by o.object_name,state

 9  order by blocks desc;

 

OBJECT_NAME          STATE                                BLOCKS

---------------------------------------------------- ----------

T1                   xcur                                      2

T1                   cr                                        1

 

 

 

范例:查看一个表的rowid和此表全部列

SQL> select rowid,t1.* from t1;

 

ROWID                      ID NAME

---------------------------- --------------------

AAAM2IAABAAAO6SAAA          1 wolex

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值