在Oracle 的運作中有一個很重要的觀念,就是盡量減少不必要的I/O,

因此當使用者查詢資料時,Oracle首先會到Database Buffer Cache內去尋找資料是否存在,如果存在就直接將資料傳回給使用者,這個動作稱為Logical Read
反之如果資料不存在Database Buffer Cache 內,那麼Oracle會將資料從Data file讀出放入Database Buffer Cache,然後傳回給使用者,這個動作稱為Physical Read

在Oracle 8以後的版本,Database Buffer Cache 又進一步分成了Defaule Pool,Keep Pool, Recycle Pool 三種pool
在Performance 的考量下, 我們可以將一些使用頻率較高的table放入Keep Pool內來減少Physical Read 的情況發生

相關工作如下
1. Monitor Buffer busy wait status.
2. Move table to keep pool
3. Monitor Keep pool size


1. Monitor Buffer busy wait status.
在將table 搬到keep pool 之前,首先我們需要知道哪些table 需要被搬到keep pool , 我們可以透過V$SEGMENT_STATISTICS 這個view來查詢segment的統計資料

Column Description
OWNER Owner of the object
OBJECT_NAME Name of the object
SUBOBJECT_NAME Name of the subobject
TABLESPACE_NAME Name of the table space to which the object belongs
TS# Tablespace number
OBJ# Dictionary object number of the object
DATAOBJ# Data object number of the object
OBJECT_TYPE Type of the object
STATISTIC_NAME Name of the statistic
STATISTIC# Statistic number
VALUE Statistic value


STATISTIC_NAME 包含了下面統計資訊,找出STATISTIC_NAME 為buffer busy waits,且VALUE欄位較高的table 放入keep pool

1. logical reads
2. buffer busy waits
3. db block changes
4. physical reads
5. physical writes
6. physical reads direct
7. physical writes direct
8. global cache cr blocks served
9.global cache current blocks served
10. ITL waits
11. row lock waits

我們透過一個簡單的Procedure 來定期收集這些資料,並將這些資料寫入Table中

● Create Monitor Table

CREATE TABLE MON_BUFFER_BUSY_WAIT
(
  MON_DATE     DATE,
  OWNER        VARCHAR2(30 BYTE),
  OBJECT_NAME  VARCHAR2(30 BYTE),
  OBJECT_TYPE  VARCHAR2(18 BYTE),
  VALUE        NUMBER
)

● Create Monitor Procedure

CREATE OR REPLACE PROCEDURE  PROC_BUFFER_BUSY_MONITOR  AS
BEGIN
   delete from mon_buffer_busy_wait where mon_date < sysdate -30;
   commit;
   INSERT INTO mon_buffer_busy_wait (mon_date, owner, object_name, object_type, value)
      (select sysdate,owner,object_name as segment_name,object_type, value as total_buff_busy_waits
          from v$segment_statistics
          where statistic_name in ('buffer busy waits') and object_type like 'TABLE%'
          and  owner in ('HR' ) and value >10);
    commit;
END;
/

● Execute monitor procedure by schedule

. /etc/profile.d/oracle.sh
. /home/oracle/.bash_profile

$ORACLE_HOME/bin/sqlplus ID/PASSWORD
exec PROC_BUFFER_BUSY_MONITOR

這樣子完成了簡單的monitor 工作


2. Move table to keep pool

在還沒決定哪些table要搬到keep pool 之前,先看看SGA中db_keep_cache_size的大小

SQL> show parameter keep                                                       
                                                                               
NAME                                 TYPE        VALUE                         
------------------------------------ ----------- ------------------------------
buffer_pool_keep                     string                                    
control_file_record_keep_time        integer     7                             
db_keep_cache_size                   big integer 0                             
                                                             

查詢v$parameter也可以

SQL> col NAME format A22
SQL> col VALUE formate A12
SQL> select name,value from v$parameter where name like 'db%size%';

NAME                   VALUE
---------------------- --------------------
db_block_size          8192
db_keep_cache_size     32212254720
db_recycle_cache_size  0
db_2k_cache_size       0
db_4k_cache_size       0
db_8k_cache_size       0
db_16k_cache_size      0
db_32k_cache_size      0
db_cache_size          1073741824

9 rows selected.

db_keep_cache_size=0表示keep pool size=0,調整keep pool size

SQL> alter system set db_keep_cache_size=10m;

接下來就可以將MON_BUFFER_BUSY_WAIT 中VALUE較高的Table 搬到keep pool 中

# alter table from keep pool to default;
alter table SCHEMA.TABLE_NAME modify partition PARTITION_NAME storage (buffer_pool default);
alter table SCHEMA.TABLE_NAME storage (buffer_pool default);

# alter table from default pool to keep pool 
alter table SCHEMA.TABLE_NAME modify partition PARTITION_NAME storage (buffer_pool keep);
alter table SCHEMA.TABLE_NAME storage (buffer_pool keep);

3. Monitor Keep Pool Size

隨著資料的增加,Keep pool 可能會不夠用,因此必須每天監控 Keep pool size,

select a.name , a.sga_size_MB, b.table_size_MB , (sga_size_MB - table_size_MB) as free_size
 from 
(
    select name,value/1024/1024  as sga_size_MB 
    from v$parameter 
    where name ='db_keep_cache_size'
) a ,
(
    select sum(bytes)/1024/1024 as table_size_MB
    from dba_segments 
    where buffer_pool='KEEP'
) b

當Keep pool 不夠時,可以透過下面SQL 來決定哪些Table 要移除keep pool

select * from (
   select a.owner,segment_name , segment_type, tablespace_name , MB , 
         nvl( b.busy_cnt,0) as busy_cnt, NVL(c.maxvalue ,0) as maxvalue
   from (
       select owner , segment_name  , segment_type , tablespace_name , sum(bytes)/1024/1024  as MB 
       from dba_segments where buffer_pool='KEEP'
       group by owner , segment_name  , segment_type , tablespace_name
   ) a left join ( 
       select  owner ,  object_name , count(*) as busy_cnt  
       from PERFSTAT.MON_BUFFER_BUSY_WAIT
       group by  owner ,  object_name
   ) b on a.owner = b.owner and a.segment_name= b.object_name  
   left join (
       select   owner ,  object_name , max(value) as maxvalue  
       from PERFSTAT.MON_BUFFER_BUSY_WAIT
       group by    owner ,  object_name
   ) c on a.owner = c.owner and a.segment_name= c.object_name 
) 
where busy_cnt = 0 order by mb desc

Reference :

http://www.oradbpedia.com/wiki/Using_the_KEEP_and_RECYCLE_Pool

arrow
arrow
    文章標籤
    [學習筆記][Oracle]Database
    全站熱搜
    創作者介紹
    創作者 rickyju 的頭像
    rickyju

    兩隻小虎,一隻豬

    rickyju 發表在 痞客邦 留言(0) 人氣()