keep池核心作用是缓存高频随机访问、数据块重用率高且体积适中的小表(如查找表),以减少io;需满足总大小≤db_keep_cache_size的70%,避免挤占其他热块,并通过v$bh.bp_id=1和v$buffer_pool_statistics验证真实驻留。
查哪些表高频访问且体积适中
keep池不是越大越好,也不是所有“热表”都适合放进去。核心判断标准是:该表被频繁随机访问(比如主键/唯一索引查找)、数据块重用率高、总大小不超过 db_keep_cache_size 的 70%。如果一张表单次全表扫描就占满 keep 池,反而会把其他热块挤出去。
常用定位方式:
- 查
v$segment_statistics中logical_reads高但physical_reads也偏高的表——说明缓存命中不足,可能受益于 KEEP - 结合 AWR 报告看 SQL 执行计划中反复出现的表,尤其是走索引回表、嵌套循环驱动表这类低延迟敏感场景
- 排除超大表(如 >500MB)和纯顺序扫描表(如日志归档表),它们更适合
db_recycle_cache_size
验证 buffer_pool=KEEP 是否真正生效
执行 alter table t1 storage(buffer_pool keep) 只是设置元数据,不等于数据块立刻进 KEEP 池。Oracle 仍按 LRU 机制加载,只是后续老化时优先保留在 KEEP 区。
确认是否起效的关键检查点:
- 查
dba_tables.buffer_pool确认值为'KEEP',但注意这仅代表“意愿”,不是“状态” - 查
v$bh关联dba_objects,过滤objd和class# = 1(data block),再看bp_id字段:1 表示在 KEEP 池(select decode(bp_id,1,'KEEP',2,'RECYCLE',3,'DEFAULT','OTHER') from v$bh where objd = &obj_id and rownum=1) - 观察
v$buffer_pool_statistics中 KEEP 池的physical_reads和db_block_gets是否随业务增长而上升——这才是真实驻留证据
避免把 LOB 段直接塞进 KEEP 池
对含 BLOB/CLOB 的表,storage(buffer_pool keep) 默认只影响表段和索引段,LOB 段仍走默认池。若想让 LOB 内容也被 KEEP,必须显式修改 LOB 子句:
alter table t2 modify lob(c2) (storage (buffer_pool keep) cache);
但要注意:
-
cache是必须加的,否则buffer_pool设置对 LOB 无效 - SecureFiles 类型的 LOB 支持更细粒度控制,BasicFiles 则受限更多,建议先查
dba_lobs.securefile - 大 LOB 块(如 chunk > 8KB)可能无法完整装入 KEEP 池单次缓冲区,导致部分块仍被置换
KEEP 池大小设置不当的典型症状
设太小:KEEP 池快速填满,新加载的 KEEP 表块被迫淘汰旧块,表现为 v$buffer_pool_statistics 中 KEEP 池的 free_buffer_wait 明显升高,且 db block gets 增长但逻辑读未降;
设太大:浪费 SGA,挤压 DEFAULT 池空间,导致普通查询物理读激增,AWR 中 “buffer busy waits” 和 “read by other session” 等等待事件上升;
稳妥做法是:先按历史 dba_segments.bytes 汇总估算总量,再加 20% 余量,初始设为 db_keep_cache_size = 2G 这类整数,上线后观察 3–5 天的 v$sgastat 和 v$buffer_pool_statistics 趋势再微调。
真正难的是持续识别“伪热表”——那些因统计信息陈旧或绑定变量窥探失准导致执行计划误判为高频的表。它们放进 KEEP 池只会掩盖优化问题,而不是解决它。











