第四章、 buffer cache 调整
1、buffer cache 功能
buffer cache: 用于存放从datafile 里读出的数据块的镜像,并共享这些数据块,采用LRU算法
buffer cache 数据块状态:
pending:数据块正在使用,状态未决
dirty: 被修改过的块,还未写入到datafile
free:
已经从cache里写入到datafile的块,可以被覆盖
LRU LIST :链接从datafile里读出的块的头部信息,一般用于free 状态的块
Checkpoint list (Dirty
list):链接dirty block ,等待dbwr 写入到datafile
db_cache_size 指定默认池大小,一般数据块都放在默认池中,默认池管理采用LRU
db_keep_cache_size :指定keep
池的大小,用于存放经常访问的小的对象的数据块。(比如索引块(常驻cache))
db_recycle_cache_size: 指定recycle
池的大小,用于存放偶尔访问对象的数据(比如偶尔做全表扫描的表的数据块)
2、设置buffer cache 的大小
对于sga 动态管理:
Granule 是内存分配的最小unit
Granule =4m sga<1g
Granule =16m sga>1g
----通过v$buffer_pool查看buffer cache
select NAME,BLOCK_SIZE,RESIZE_STATE,CURRENT_SIZE,BUFFERS from
v$buffer_pool
NAME BLOCK_SIZE RESIZE_STA
CURRENT_SIZE BUFFERS
--------------------------------------------------
---------- ---------- ------------ ----------
DEFAULT
8192 STATIC 156 19461
16384 STATIC 12
756
通过oracle advisory 调整buffer cache 的大小
15:01:33 SYS@ test1>show parameter db_cache
NAME TYPE
VALUE
------------------------------------ -----------
------------------------------
db_cache_advice string
ON
---默认oracle 会通过顾问来产生一个建议的大小
Buffer Pool Advisory DB/Inst: TEST1/test1 End Snap: 12
-> Only rows
with estimated physical reads >0 are displayed
-> ordered by Pool,
Block Size, Buffers For Estimate
Est
Phys Estimated Est
Size for Size Buffers
Read Phys Reads Est Phys % dbtime
P Est (M) Factr (thousands)
Factr (thousands) Read Time for Rds
--- -------- ----- ------------
------ -------------- ------------ --------
D 16 .1 2
1.4 6 28 32.9
D 32 .2 4
1.1 5 22 25.9
D 48 .3 6
1.1 5 21 24.7
D 64 .4 8
1.0 5 20 23.5
D 80 .5 10
D 96 .6 12
D 112 .7 14
D 128 .8 16
D 144 .9 18
D 160 1.0 20
D 164 1.0 20
size for est: buffer cache 期望的大小
size factr: 期望尺寸和实际尺寸的比率
buffers:
缓存的个数(数据块),以千为单位
est phys read factr:产生物理读得因子
从以上可以看出,buffer cache 在64m 是比较合适的,在16m ,产生物理读得可能性增加了40%
15:05:05 SYS@ test1>SELECT
size_for_estimate,buffers_for_estimate,estd_physical_read_factor,estd_physical_reads
FROM
V$DB_CACHE_ADVICE WHERE name = ‘DEFAULT‘ AND block_size = (SELECT value FROM
V$PARAMETER WHERE name = ‘db_block_size‘)AND advice_status = ‘ON‘;
SIZE_FOR_ESTIMATE BUFFERS_FOR_ESTIMATE ESTD_PHYSICAL_READ_FACTOR
ESTD_PHYSICAL_READS
----------------- --------------------
------------------------- -------------------
12 1497
2.1167 9421
24 2994
1.2083 5378
36
4491 1.0028 4463
48
5988 1 4451 ;当前比较合适的尺寸
60
7485 1 4451
72 8982 1 4451
84 10479 1 4451
96 11976 1
4451
108 13473 1
120 14970 1
132 16467
1 4451
144 17964
156 19461
168
20958 1 4451
180
22455 1 4451
192
23952 1 4451
204 25449 1 4451
216 26946
228 28443
240
29940 1 4451
20 rows selected.
3、buffer cache 调优目标
在oltp的库中,server 进程可以在buffer cache
找到所需要的块,提高块的命中率
1)通过oracle 顾问设置一个合适的尺寸,并提高块的命中率
2)设置不同的cache :default 、keep 、recycle
3)将表缓存到cache
4)对于排序和并行读,跳过buffer cache
-------buffer cache 命中率
physical reads:物理读,直接从磁盘读取数据块到buffer cache
physical reads direct:
物理直接读,从磁盘读取数据块到pga ,跳过sga(一般比如用于排序操作)
physical reads direct (lob):
对大对象的直接读
session logical reads:会话读取的所有数据块次数,包括物理读和一致性读等
13:56:17 SYS@ test1>SELECT ROUND(1 - ((physical.value - direct.value -
lobs.value) / logical.value),3) *100||‘%‘
13:56:19 2 "Buffer Cache Hit
Ratio"
13:56:27 3 FROM v$sysstat physical,
13:56:38 4 v$sysstat
direct,
13:56:47 5 v$sysstat lobs,
13:56:54 6 v$sysstat
logical
13:57:02 7 WHERE physical.name = ‘physical reads‘
13:57:13 8
AND direct.name = ‘physical reads direct‘
13:57:22 9 AND lobs.name =
‘physical reads direct (lob)‘
13:57:32 10 AND logical.name = ‘session
logical reads‘;
Buffer Cache Hit
Ratio
-----------------------------------------
99.5%
Elapsed: 00:00:00.04
13:57:41 SYS@ test1>
--对于OLTP的库,应该稳定在95% 以上。
4、通过建立不同的cache ,合理的使用buffer cache 空间,提高buffer cache的命中率
15:34:31 SYS@
test1>alter system set db_keep_cache_size=12m;
System altered.
Elapsed: 00:00:00.18
15:34:39 SYS@ test1>alter system set
db_recycle_cache_size=12m;
Elapsed: 00:00:00.09
15:34:53 SYS@ test1>show parameter cache
db_cache_size big integer 32M
db_keep_cache_size
big integer 12M
db_recycle_cache_size big
integer 12M
object_cache_max_size_percent integer
10
object_cache_optimal_size integer
102400
session_cached_cursors integer 20
案例:
使用keep 和recycle 池
---默认所有对象的块都会放入到default cache
15:37:24 SCOTT@ test1>select segment_name,segment_type,bytes/1024
,buffer_pool from user_segments
15:37:34 2 where segment_name in
(‘EMP‘,‘PK_EMP‘);
SEGMENT_NAME SEGMENT_TYPE BYTES/1024
BUFFER_
------------------------------ ------------------ ----------
-------
EMP TABLE 64
PK_EMP INDEX 64
Elapsed: 00:00:00.16
15:37:38 SCOTT@ test1>
----把经常调用的小的对象的块放入到keep (比如索引)
15:39:08 SCOTT@ test1>alter index pk_emp storage (buffer_pool keep);
Index altered.
Elapsed: 00:00:00.21
----对于偶然做全表扫描的表的数据块可以放入到recycle
15:39:34 SCOTT@ test1>alter table emp storage(buffer_pool recycle);
Table altered.
Elapsed: 00:00:00.07
15:40:06 SCOTT@ test1>select
segment_name,segment_type,bytes/1024 ,buffer_pool from user_segments
15:40:16
2 where segment_name in (‘EMP‘,‘PK_EMP‘);
RECYCLE
PK_EMP INDEX 64 KEEP
Elapsed: 00:00:00.03
15:40:23 SCOTT@ test1>
15:50:01 SCOTT@ test1>select ename,sal,deptno from emp where
deptno=10;
ENAME SAL DEPTNO
---------- ---------- ----------
CLARK
2450 10
KING 5000 10
MILLER
1300 10
----查看用户会话读取的数据块情况
15:49:19 SYS@ test1>select
s.username,io.block_gets,io.consistent_gets,io.physical_reads
15:49:33 2
from v$sess_io io,v$session s
15:49:37 3 where io.sid=s.sid and
s.username is not null;
USERNAME BLOCK_GETS CONSISTENT_GETS
PHYSICAL_READS
------------------------------ ---------- ---------------
--------------
SYS 9 899
61
SYS 0 16
1
Elapsed: 00:00:00.01
15:49:48 SYS@ test1>/
SCOTT 0 99
Elapsed: 00:00:00.02
block_gets :在做dml 操作时读取的数据块
consistent_gets: SELECT
时读取的数据块
physical_reads :物理读
---KEEP 和 rcycle 池使用
14:20:27 SCOTT@ test1>alter index pk_emp storage(buffer_pool keep);
15:03:39 SCOTT@ test1>alter table emp storage(buffer_pool recycle);
14:36:09 SCOTT@ test1>select * from emp;
14:36:26 SYS@ test1>/
SCOTT 0 39
SYS 171 8717
549
14:40:07 SCOTT@ test1>update emp set sal=sal+1000 where deptno=20;
5 rows updated.
-----当update
操作时,由于emp表的块都放在recycle池中,select查询完成,这些数据块被消除;所以此次update操作,产生了物理读。
14:36:32
SYS@ test1>/
SCOTT 6 2999
94
Elapsed: 00:00:00.00
14:40:22 SCOTT@ test1>select * from emp1;
14:40:25 SYS@ test1>/
SCOTT 6 3069
101
14:41:16 SCOTT@ test1>update emp1 set sal=sal+1000 where deptno=20;
8 rows updated.
------emp表数据块在default 池,所以这些数据块被共享在buffer cache 里,在做update
时候,不会产生物理读。
14:41:22 SYS@ test1>/
SCOTT 14 3082
14:41:46 SYS@ test1>
15:07:51 SCOTT@
test1>analyze table emp estimate statistics;
Table analyzed.
Elapsed: 00:00:00.44
15:11:34 SCOTT@ test1>select * from emp where
ename=‘SCOTT‘;
EMPNO ENAME JOB MGR HIREDATE SAL COMM
DEPTNO
---------- ---------- --------- ---------- --------- ----------
---------- ----------
7788 SCOTT ANALYST 7566 19-APR-87
9000 20
Execution
Plan
----------------------------------------------------------
Plan hash
value: 3220259315
---------------------------------------------------------------------------------------------
|
Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
Time
0 | SELECT STATEMENT | | 1 | 32 | 2 (0)|
00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 |
32 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN |
EMP_ENAME_IND | 1 | | 1 (0)| 00:00:01
Predicate Information (identified by operation
id):
---------------------------------------------------
2 - access("ENAME"=‘SCOTT‘)
Statistics
recursive calls
0 db block gets
3 consistent
gets
0 physical reads
0 redo size
828
bytes sent via SQL*Net to client
384 bytes received via SQL*Net from
client
2 SQL*Net roundtrips to/from client
0 sorts
(memory)
0 sorts (disk)
1 rows processed
15:11:43 SCOTT@ test1>
15:10:46 SYS@ test1>select
name,PHYSICAL_READS,DB_BLOCK_GETS,CONSISTENT_GETS from
v$buffer_pool_statistics;
NAME PHYSICAL_READS DB_BLOCK_GETS
CONSISTENT_GETS
-------------------- -------------- -------------
---------------
KEEP 2 0
6
RECYCLE 5 0
20
DEFAULT 4401 4271
85050
DEFAULT 0 0 0
5、关于buffer cache的等待事件
测试案例:
15:06:01 SCOTT@ test1>alter session enable parallel dml;
Session altered.
15:06:04 SCOTT@ test1> begin
15:06:18 2
for i in 1..500000 loop
15:06:18 3 execute immediate ‘insert /*+
parallel (4) */ into t1 values (‘||i||‘)‘;
15:06:18 4 end
loop;
15:06:18 5 end;
15:06:18 6 /
16:00:20 SYS@ test1>select event ,total_waits from
v$system_event
16:00:39 2 where event in (‘free buffer waits‘,‘buffer
busy waits‘);
EVENT
TOTAL_WAITS
----------------------------------------------------------------
-----------
buffer busy waits
16:01:06 SYS@ test1>
1 select name ,PARAMETER1,PARAMETER2 ,PARAMETER3 from v$event_name
2*
where name like ‘buffer busy%‘
NAME PARAMETER1 PARAMETER2
PARAMETER3
-------------------- -------------------- --------------------
--------------------
buffer busy waits file# block#
class#
buffer busy group# obj#
block#
------通过:
PARAMETER1: 处于等待事件中块所在的file#
PARAMETER2: 处于等待事件中块所在的
这样就可以通过两个参数来判断,这些块的类型(段头块、data 块、索引块、undo 块)
free buffer waits: server 进程从datafile 读取block 到buffer cache时,一般因为在buffer
cache没有空闲的buffer
解决: 增加buffer cache大小,或者让dbwr 写脏块释放空间
buffer busy
waits: 一般多个server 进程同时访问一个块
1)段头部:在做insert 时,因为free list 列表而引起的等待
解决:1)增加free list
2)将段空间管理采用自动方式(位图)
2)普通数据块:多个进程访问一个块
解决: 1)用小的块
2)增大pctfree
3)如果是索引块,索引是通过序列生成的主键,采用反向索引
3)undo 块:
多个server进程同时访问undo
解决: 1)对事务采用分批提交
2)增加rollback段或采用undo 表空间
---查询busy block 数据块类型及段
16:00:20 SYS@ test1> select ‘Segment Header‘
class, a.segment_type, a.segment_name, a.partition_name from dba_segments a,
v$session_wait b
where a.header_file = b.p1 and a.header_block = b.p2 and
b.event = ‘buffer busy waits‘
union
select ‘Freelist Groups‘ class,
a.segment_type, a.segment_name, a.partition_name from dba_segments a,
where b.p2 between a.header_block + 1 and (a.header_block +
a.freelist_groups) and a.header_file = b.p1 and a.freelist_groups > 1 and
select a.segment_type || ‘ block‘
class, a.segment_type, a.segment_name, a.partition_name from dba_extents a,
where b.p2 between a.block_id and a.block_id + a.blocks - 1
and a.file_id = b.p1 and b.event = ‘buffer busy waits‘
and not exists
(select 1 from dba_segments where header_file = b.p1 and header_block =
b.p2);
buffer busy waits:
#!/bin/bash
export ORACLE_SID=test1
count=0
while [ $count -lt 1000 ]
do
sqlplus ‘sys/oracle as sysdba‘<<EOF
update tb1 set object_id=1000 ;
rollback;
EOF
count=`expr $count + 1`
done
[oracle@rh6 ~]$ cat 4.sh
update tb1 set object_name=‘aaa‘ ;
[oracle@rh6 ~]$
13:35:30 SYS@ test1 > select
size_for_estimate,SIZE_FACTOR,buffers_for_estimate,estd_physical_read_factor,estd_physical_reads
13:36:11
2 FROM V$DB_CACHE_ADVICE WHERE name = ‘DEFAULT‘ AND block_size = (SELECT
value FROM V$PARAMETER WHERE name = ‘db_block_size‘)AND advice_status =
‘ON‘;
SIZE_FOR_ESTIMATE SIZE_FACTOR BUFFERS_FOR_ESTIMATE ESTD_PHYSICAL_READ_FACTOR
----------------- ----------- --------------------
4 .25
496 1.0955 71824
8 .5 992 1.0481
68718
12 .75 1488
1.0229 67070
16 1 1984
1 65565
20 1.25
2480 .9727 63772
24 1.5 2976 .9531
62492
28 1.75 3472
.9377 61483
32 2 3968
.9187 60235
8 rows selected.
13:36:12 SYS@ test1 >/
496 1.0963 79584
8 .5 992 1.05
76223
1.0239 74327
1 72591
2480 .9719 70552
24 1.5 2976 .9508
69023
.9335 67764
.9129 66267
13:36:49 SYS@ test1 >select event ,total_waits
from v$system_event
13:37:04 2 where event in (‘free buffer waits‘,‘buffer
free buffer waits
3623
4
13:37:10 SYS@ test1 >show parameter cache
client_result_cache_lag big
integer 3000
client_result_cache_size big integer
db_16k_cache_size big integer 12M
db_2k_cache_size
big integer 0
db_32k_cache_size big
integer 0
db_4k_cache_size big integer
db_8k_cache_size big integer 0
db_cache_advice
string ON
db_cache_size big
integer 16M
db_flash_cache_file
string
db_flash_cache_size big integer
db_keep_cache_size big integer
16M
db_recycle_cache_size big integer
result_cache_max_result integer
5
result_cache_max_size big integer 768K