Introduction
众所周知缓存是关系型数据库中一种重要机制,内存的访问速度远远高于磁盘,把经常使用的数据存放于内存中来提高检索速度已不是什么新鲜事了。
Result cache overview
我们知道数据库在构建一个 SQL 查询结果时,不仅需要在访问数据上消耗时间,数据的排序、聚合以及连接操作也会消耗一部分时间。对此 Oracle 在 11GR1 引入了结果集缓存( Result Cache ),目的就是将结果直接放入内存中来节省构建结果集所花费的时间和资源。引擎可以直接返回结果,而不必在 Cache 中读取数据。
我们可以把 SQL 执行概括为三大阶段 :
1. 从存储获取数据到内存(对于尚未在缓存中的数据)
2. 对缓存数据集进行筛选
3. 返回结果集给客户端

Result Cache 启用的情况下,不仅会把结果集返回给客户端,而且还会把结果集缓存在 Shared Pool 特定一块区域内。当任何客户端执行类似 SQL 返回相同结果时, Oracle 会跳过 1 和 2 直接从 result cache 中返回结果,大大提高了性能。

Result Cache 可以分为: Server Result Cache 和 Client Result Cache
Server Result Cache :对于 Server Result Cache: 服务器端结果集缓存,在 Shared Pool 中单独分配一块内存来进行结果缓存。

Client Result Cache :可以通过客户端内存来缓存查询结果集,并可以在所有 session 间共享,当查询反复执行时,查询结果可以直接从客户段的缓存中获得,从而极大地提高应用效率。
Result Cache 特性可以通过一些动态参数进行控制。用以定义结果集的内存池的大小,触发的方式等。

默认情况下 Result Cache 是开启的,所有开发人员都可以使用该特性。
1. 表级别使用

2. 语句级别使用

默认情况下,如果基础表发生改变,则
Oracle
会将
Result Cache
中的结果集置为无效。使得客户端不会从结果缓存中获取过时的数据。
当查询运行时,
Result Cache
将自动填充,然后在提交
DML
时无效。 Result Cache
使用监控(相关查看包及视图)
v$result_cache_statistics
内存统计数据v$result_cache_object
对象跟属性v$result_cache_dependency
显示结果的依赖关系v$result_cache_memory
显示内存块及统计数据
limits
Result Cache 与其他 Oracle 部分内存池类似也是通过 Latch 锁进行保护,读取缓存池时需要持有共享锁,修改时(用于添加新的结果集或使现有结果集无效)需要持有排他锁,以避免别的会话同时访问。
因此频繁的更新 Result Cache 中对应的表格会引起 Latch 锁的争用(特别是 RC Latch ),

如果在某些对象上几乎所有查询都使用结果缓存,情况会更糟。
Case

某客户从 AIX 平台迁到 x86 稳定运行半个月后,高峰期时常出现卡顿,提取故障点的 awr 及 ash 报告。 从上述等待事件可以看出数据库大部分时间都花在 enq: TX - row lock contention 和 latch free 上。
第一反应可能觉得是 enq: TX - row lock contention 引起的故障,一开始我也犯了同样的错误,但随后与开发沟通后发现从迁移之后程序代码并无变化。既然业务逻辑没有改变 TX 锁引起此次故障可能性不大,初步判定是由于 latch free 使得 TX 锁加剧。继续查看 latch free 相关的信息。


latch 的信息统计,定位主要元凶是 Result Cache:RC Latch 。
查看 result 相关参数其中 result_cache_mode 为 force ,解决办法可以直接把 result_cache_mode 改成 manual 或直接禁用 result cache 设置 result_cache_max_size 为 0 。
Conclusion
Result Cache 是 Oracle 又一个进步,能大幅提升性能,但也像其他特性一样不是所有的会话都适用。
