浅谈Oracle Result Cache—-结果集缓存

众所周知,内存的访问速度远远高于磁盘,把经常使用的数据存放于内存中来提高检索速度已不是什么新鲜事了。Cache 是内存中的一片区域,也叫缓存,如今关系型数据库正是利用这一种重要机制,使得访问数据库的性能突飞猛进。

Result Cache简述

数据库在构建一个SQL查询结果时,不仅需要在访问数据上消耗时间,数据的排序、聚合以及连接操作也会消耗一部分时间。对此Oracle 在11g R1版本中引入了Result 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,通过在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 显示内存块及统计数据

Result Cache的影响

Result Cache的读取和修改与其他Oracle部分内存池的读取修改情况类似,也是通过Latch锁进行保护,读取缓存池时需要持有共享锁,修改时(用于添加新的结果集或使现有结果集无效)需要持有排他锁,以避免其他会话同时访问。

因此频繁的更新Result Cache中对应的表格会引起Latch锁的争用(特别是RC Latch)

如果在某些对象上几乎所有查询都同时并发使用Result Cache,情况会更糟。

下面以一个具体的案例介绍:

某客户从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。

结论

Result Cache是Oracle又一个进步,能大幅提升性能,但也像其他特性一样,不是所有的会话都适用。