Buffer Cache

Buffer Cache:default pool & keep pool & recycle pool

     Keep Buffer Pool 的作用是緩存那些需要經常查詢的對象但又容易被默認緩衝區置換出去的對象,按慣例,Keep pool設置爲合理的大小,以使其中存儲的對象不再age out,也就是查詢這個對象的操作不會引起磁盤IO操作,可以極大地提高查詢性能。

    默認的情況下 db_keep_cache_size=0,未啓用,如果想要啓用,需要手工設置db_keep_cache_size的值,設置了這個值之後 db_cache_size 會減少。

    並不是我們設置了keep pool 之後,熱點表就一定能夠緩存在 keep pool ,keep pool 同樣也是由LRU 鏈表管理的,當keep pool 不夠的時候,最先緩存到 keep pool 的對象會被擠出,不過與default pool 中的 LRU 的管理方式不同,在keep pool 中表永遠是從MRU 移動到LRU,不會由於你做了FTS而將表緩存到LRU端,在keep pool中對象永遠是先進先出。

    Recycle Buffer Pool正好相反。Recycle Buffer Pool用於存儲臨時使用的、不被經常使用的較大的對象,這些對象放置在Default Buffer Pool顯然是不合適的,這些塊會導致過量的緩衝區刷新輸出,而且不會帶來任何好處,因爲等你想要再用這個塊時,它可已經老化退出了緩存。要把這些段與默認池和保持池中的段分開,這樣就不會導致默認池和保持池中的塊老化而退出緩存。

    

--表緩存   

alter table ..... storage(buffer_pool keep);     

--查看哪些表被放在緩存區 但並不意味着該表已經被緩存   

select table_name from dba_tables where buffer_pool='keep';   

--查詢到該表是否已經被緩存   

select table_name,cache,buffer_pool from user_TABLES where cache like '%Y';   

--已經加入到KEEP區的表想要移出緩存,使用   

alter table table_name nocache;   

--批量插入ORACLE建議用 

insert all into ... insert into  ... select  1 from dual;  

insert all into ... insert into ...select 1 from dual;   

--查詢當前用戶下表的情況   

select table_name,cache,buffer_pool from user_TABLES;   

--對於普通LOB類型的segment的cache方法   

alter table t2 modify lob(c2) (storage (buffer_pool keep) cache);   

--取消緩存   

alter table test modify lob(address) (storage (buffer_pool keep) nocache);   

--查詢段   

select segment_name,segment_type,buffer_pool from user_segments;   

--對基於CLOB類型的對象的cache方法     

alter table lob1 modify lob(c1.xmldata) (storage (buffer_pool keep) cache);    

  --查詢該用戶下所有表內的大字段情況   

select column_name,segment_name from user_lobs; 

 

來一段Tom關於Multiple Buffer Pools的解釋,講解得很清楚:

實際上,這3 個池會以大體相同的方式管理塊;將塊老化或緩存的算法並沒有根本的差異。這樣做的目標是讓DBA 能把段聚集到“熱”區(hot)、“溫”區(warm)和“不適合緩存”區(do not care to cache)。

理論上講,默認池中的對象應該足夠熱(也就是說,用得足夠多),可以保證一直呆在緩存中。緩存會把它們一直留在內存中,因爲它們是非常熱門的塊。可能還有 一些段相當熱門,但是並不太熱;這些塊就作爲溫塊。這些段的塊可以從緩存刷新輸出,爲不常用的一些塊(“不適合緩存”塊)騰出空間。爲了保持這些溫段的塊得到緩存,可以採取下面的某種做法:將這些段分配到保持池,力圖讓溫塊在緩衝區緩存中停留得更久。將“不適合緩存”段分配到回收池,讓回收池相當小,以便塊能快速地進入緩存和離開緩存(減少管理的開銷)。這樣會增加DBA 所要執行的管理工作,因爲要考慮3 個緩存,要確定它們的大小,還要爲這些緩存分配對象。還要記住,這些池之間沒有共享,所以,如果保持池有大量未用的空間,即使默認池或回收池空間不夠用了, 保持池也不會把未用空間交出來。總之,這些池一般被視爲一種非常精細的低級調優設備,只有所有其他調優手段大多用過之後才應考慮使用。



#####################################################################


Multiple buffer pools let you address these differences. You can use a KEEP buffer pool to maintain frequently accessed segments in the buffer cache, and a RECYCLE buffer pool to prevent objects from consuming unnecessary space in the cache. When an object is associated with a cache, all blocks from that object are placed in that cache. Oracle maintains a DEFAULT buffer pool for objects that have not been assigned to a specific buffer pool. The default buffer pool is of size DB_CACHE_SIZE. Each buffer pool uses the same LRU replacement policy (for example, if the KEEP pool is not large enough to store all of the segments allocated to it, then the oldest blocks age out of the cache).


我同事認爲:buffer pool和keep pool 都使用了lru算法,oracle就是給分了兩個池,取了不同的名字而已;裏面機制都是一樣的;

而我認爲:雖然buffer pool和keep pool 都使用了lru算法,但是應該存在如下的區別:

          假設一個sql走了一個索引A,A索引有100個數據塊,其中該sql訪問了5個數據塊;如果該索引使用了buffer pool,該sql將會導致5個數據塊讀入buffer pool,而如果該索引使用了keep pool,那100個塊都將讀入keep pool;請大家一塊來討論一下。。


好像我錯了 :
只緩存了數據讀取的數據,而不是整個索引去讀取;
CREATE TABLE T_KEEP AS SELECT * FROM DBA_SOURCE;
CREATE INDEX IND_T_NAME ON T_KEEP (NAME) STORAGE (BUFFER_POOL KEEP);
ALTER TABLE T_KEEP STORAGE (BUFFER_POOL KEEP);
SQL> SELECT SUM(BLOCKS) FROM USER_EXTENTS WHERE SEGMENT_NAME = 'T_KEEP';

SUM(BLOCKS)
-----------
       5760
SQL> SELECT OBJECT_NAME, A.STATUS, COUNT(*)
  2   FROM V$BH A, USER_OBJECTS B
  3   WHERE A.OBJD = B.OBJECT_ID
  4   AND OBJECT_NAME IN ('T_KEEP')
  5   GROUP BY OBJECT_NAME, A.STATUS;

OBJECT_NAME                    STATUS    COUNT(*)
------------------------------ ------- ----------
T_KEEP                         xcur            98

SQL> SELECT SUM(BLOCKS) FROM USER_EXTENTS WHERE SEGMENT_NAME = 'IND_T_NAME';

SUM(BLOCKS)
-----------
        768

SQL> SELECT OBJECT_NAME, A.STATUS, COUNT(*)
  2       FROM V$BH A, USER_OBJECTS B
  3       WHERE A.OBJD = B.OBJECT_ID
  4       AND OBJECT_NAME IN ('IND_T_NAME')
  5       GROUP BY OBJECT_NAME, A.STATUS;

OBJECT_NAME                    STATUS    COUNT(*)
------------------------------ ------- ----------
IND_T_NAME                     xcur            21
     
     
SET AUTOT ON STAT
SQL> SELECT COUNT(1) FROM T_KEEP where NAME='PRPJPLANFEELOCK';

  COUNT(1)
----------
        51


Statistics
----------------------------------------------------------
         63  recursive calls
          0  db block gets
         82  consistent gets
         16  physical reads
          0  redo size
        515  bytes sent via SQL*Net to client
        492  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> SELECT OBJECT_NAME, A.STATUS, COUNT(*)
  2           FROM V$BH A, USER_OBJECTS B
  3           WHERE A.OBJD = B.OBJECT_ID
  4           AND OBJECT_NAME IN ('IND_T_NAME')
  5           GROUP BY OBJECT_NAME, A.STATUS;

OBJECT_NAME                    STATUS    COUNT(*)
------------------------------ ------- ----------
IND_T_NAME                     xcur            37

讀取前緩存裏有21個數據塊,執行sql使用了16個物理讀,執行sql後緩存中只有37(21+16)個,說明只緩存了讀取的數據塊;



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章