oracle server result cache

Server result cache

oracle 从 11g 开始在 shared pool 中划分了一个新的独立内存区域 server result cache ,用来缓存频繁使用的结果集。与缓冲区缓存数据块不同,server result cache 缓存的是结果集,包含 SQL query result cache 和 PL/SQL function result cache ,他们共用相同的基础结构。

相关参数

SQL> show parameter result_cache

NAME				     TYPE	 VALUE
------------------------------------ ----------- ------------------------------
client_result_cache_lag 	     big integer 3000
client_result_cache_size	     big integer 0
result_cache_max_result 	     integer	 5
result_cache_max_size		     big integer 4064K
result_cache_mode		     string	 MANUAL
result_cache_remote_expiration	     integer	 0

result_cache_max_result : 指定任一结果可使用的最大高速缓存量。默认值为5%,但可指定1 到100 之间的任一百分比值。

result_cache_max_size : 指定用来作为结果缓存的共享池内存的大小,假设被设置为0,表示这个特性被禁用。这个参数大于0的值四舍五入到32 KB的一个整数倍。

result_cache_mode : 指定 result cache 的模式。默认值是 MANUAL 。
参数值可以是:AUTO、MANUAL、FORCE

  • AUTO : 优化程序将根据重复的执行操作确定将哪些结果存储在高速缓存中(网上说同样的 SQL 执行3次就会被缓存,没有在官方文档找到相应的说明,实验没有验证这种说法)。
  • MANUAL : 默认值。此时只有使用 RESULT_CACHE hint 的查询会使用 result cache 。
  • FORCE : 此时所有没有使用 NO_RESULT_CACHE hint 的查询都会使用 result cache 。

另外,可以通过设置 Table Annotation ,指定表的 RESULT_CACHE (MODE FORCE) 来使该表的查询结果强制使用 result cache 。它的优先级高于 result_cache_mode 参数,但是低于 hint 。

result_cache_remote_expiration : 指定缓存远程对象的有效期(单位为分钟),默认值为 0 。由于基于远程对象的结果集无法由于远程对象的变更而自己主动地变为无效,通常保持默认值 0,这意味着基于远程对象的查询结果的缓存是被禁止的。将此参数设置为非零值会产生过时的结果(例如,如果在远程数据库中修改了结果所使用的远程表)。

result_cache_max_result 和 result_cache_max_size 是系统级别的设置, result_cache_mode
和 result_cache_remote_expiration 能够在会话级别改动。

SQL query result cache

数据库能在 SQL query result cache 中缓存查询和查询片段的结果,将此缓存结果用于将来的查询和查询片段。大多数应用程序受益于这种性能改善。假设应用程序将重复执行相同的 SELECT 语句。如果结果会被缓存,则数据库会将其立即返回。通过这种方式,数据库避免了重读块和重计算结果等昂贵操作。每当事务修改了数据或用于构造该缓存结果的数据库对象元数据时,数据库自动使其高速缓存结果无效。

示例:

统计各部门的平均工资

SQL> explain plan for select /*+ result_cache +*/ deptno,avg(sal) from scott.emp group by deptno;

Explained.

SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4067220884

--------------------------------------------------------------------------------------------------
| Id  | Operation           | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                            |    14 |   364 |     4  (25)| 00:00:01 |
|   1 |  RESULT CACHE       | aqx1hm27sfwyy4x3jgcchs4sjr |       |       |            |          |
|   2 |   HASH GROUP BY     |                            |    14 |   364 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| EMP                        |    14 |   364 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

Result Cache Information (identified by operation id):
------------------------------------------------------

   1 - column-count=2; dependencies=(SCOTT.EMP); name="select /*+ result_cache +*/ deptno,avg(sal) from scott.emp group by deptno"

Note
-----
   - dynamic sampling used for this statement (level=2)

19 rows selected.

从上面的执行计划中可以看出加了 result_cache 的 hint 后,该 SQL 使用了 result cache 。
oracle 使用 V$RESULT_CACHE_OBJECTS 来存储这些缓存结果集的信息。由于上面只生成了执行计划,并没有执行,所以我们要执行一次这个 SQL 才能把结果缓存在 result cache 中。

SQL> select /*+ result_cache +*/ deptno,avg(sal) from scott.emp group by deptno;

    DEPTNO   AVG(SAL)
---------- ----------
        30 1566.66667
        20       2175
        10 2916.66667

3 rows selected.

SQL> SELECT TYPE,STATUS,NAME,CACHE_ID FROM V$RESULT_CACHE_OBJECTS WHERE UPPER(STATUS) = 'PUBLISHED';

TYPE       STATUS    NAME                                                                             CACHE_ID
---------- --------- -------------------------------------------------------------------------------- ------------------------------
Dependency Published SCOTT.EMP                                                                        SCOTT.EMP
Result     Published select /*+ result_cache +*/ deptno,avg(sal) from scott.emp group by deptno       aqx1hm27sfwyy4x3jgcchs4sjr

2 rows selected.

我们可以看出 oracle 维护了这个 SQL 查询所依赖的对象。那一旦该对象发生了变化,oracle 会自动将缓存的查询结果集设置为无效状态。

SQL> update scott.emp set ename='BOB' where empno=7369;

1 row updated.

SQL> commit;

Commit complete.

SQL> SELECT TYPE,STATUS,NAME,CACHE_ID FROM V$RESULT_CACHE_OBJECTS WHERE CACHE_ID='aqx1hm27sfwyy4x3jgcchs4sjr';

TYPE       STATUS    NAME                                                                             CACHE_ID
---------- --------- -------------------------------------------------------------------------------- ------------------------------
Result     Invalid   select /*+ result_cache +*/ deptno,avg(sal) from scott.emp group by deptno       aqx1hm27sfwyy4x3jgcchs4sjr

1 row selected.

可以看到,我们只是修改了该 SQL 依赖对象上不相关的一个信息,刚才缓存的结果就变成了 Invalid 状态。

适用场景

  • 大量重复的 SELECT 查询语句;
  • SQL 依赖对象的数据不经常变化;
  • 返回的结果集较小;

使用限制

包含对以下内容的查询,不会使用 result cache:

  • 临时表
  • 字典表
  • 不确定的 PL/SQL 函数
  • 序列的 CURRVAL 和 NEXTVAL
  • CURRENT_DATE、SYSDATE 等返回数据不稳定的系统函数

查询结果集大于可用缓存结果集可用空间的不会被缓存;
result cache 采用 LRU 算法管理内存空间。

PL/SQL function result cache

PL/SQL function result cache 缓存函数的结果集。若不使用缓存功能,每次调用花 1 秒钟的函数,调用该函数 1000 次将花时间 1000 秒。而缓存后,以相同的输入调用函数 1000 次总共仅需要时间 1 秒。对于在相对静态的数据上被频繁调用的函数,结果缓存是一个很好的选择。

PL/SQL function code 可以包括一个缓存其结果的请求。调用此函数时,系统将检查缓存。如果高速缓存中包含之前使用相同参数值调用该函数的结果缓存,则系统将缓存结果返回给调用程序,而不会重新执行函数体。如果缓存中不包含其结果,则系统执行函数体,并在将控制返回给调用程序前,将其(针对这些参数值的)结果添加到缓存中。

您可以指定用于计算缓存结果的数据库对象,如果其中任何对象被更新,则缓存结果变为无效且必须重新计算。

缓存中可能会积累很多的结果缓存 ——当调用每个结果缓存函数时,每个不同的参数组合都形成一个结果缓存。如果数据库需要更多内存,则它会移除一个或多个缓存结果。

PL/SQL function result cache 和 SQL query result cache 共享一个 result cache 内存区域。

要使用 PL/SQL function result cache ,需要通过显示指定 RESULT_CACHE 关键字。可以选择包括 RELIES_ON 子句,以指定函数结果依赖的任何表或视图。

示例:

SQL> CREATE OR REPLACE
FUNCTION empName (eno NUMBER)
RETURN VARCHAR2
RESULT_CACHE RELIES_ON (scott.emp)
IS
	result VARCHAR2(10);
BEGIN
	SELECT ename INTO result
	FROM scott.emp
	WHERE empno = eno;
	RETURN result;
END;
/

Function created.

SQL> select empName(7369) from dual;

EMPNAME(7369)
------------------------------
BOB

1 row selected.

SQL> SELECT RCO.TYPE,RCO.STATUS,RCO.NAME,RCO.CACHE_ID,RCO.CACHE_KEY,RCO_DEPENDENCY.TYPE DEPENDENT_TYPE,RCO_DEPENDENCY.STATUS DEPENDENT_STATUS,RCO_DEPENDENCY.NAME DEPENDENT_NAME FROM V$RESULT_CACHE_OBJECTS RCO
JOIN V$RESULT_CACHE_DEPENDENCY RCD
ON RCD.RESULT_ID = RCO.ID
JOIN V$RESULT_CACHE_OBJECTS RCO_DEPENDENCY
ON RCD.DEPEND_ID = RCO_DEPENDENCY.ID;

TYPE       STATUS    NAME                                                         CACHE_ID                       CACHE_KEY                      DEPENDENT_ DEPENDENT DEPENDENT_NAME
---------- --------- ------------------------------------------------------------ ------------------------------ ------------------------------ ---------- --------- --------------------
Result     Published "SYS"."EMPNAME"::8."EMPNAME"#762ba075453b8b0d #1             08zynh929vwk261u11pq64h9zu     33z0nabqbda80cgcsudkvpm005     Dependency Published SYS.EMPNAME
Result     Published "SYS"."EMPNAME"::8."EMPNAME"#762ba075453b8b0d #1             08zynh929vwk261u11pq64h9zu     33z0nabqbda80cgcsudkvpm005     Dependency Published SCOTT.EMP

2 rows selected.

可以看出,oracle 缓存了一个结果集,这个结果集依赖对象有 SYS.EMPNAME 函数和 SCOTT.EMP 表两个。这两个对象有任何一个发生变化,oracle 都会将对应的 result cache 设为 Invalid 。

当同一个函数被传入的参数值完全相同时,oracle 将试图从缓存中直接获得结果;当同一个函数被传入的参数值不同时,oracle 会缓存两份返回结果,他们的依赖对象时一样的。

SQL> select empName(7788) from dual;

EMPNAME(7788)
---------------------------------------
SCOTT

1 row selected.

SQL> SELECT RCO.TYPE,RCO.STATUS,RCO.NAME,RCO.CACHE_ID,RCO.CACHE_KEY,RCO_DEPENDENCY.TYPE DEPENDENT_TYPE,RCO_DEPENDENCY.STATUS DEPENDENT_STATUS,RCO_DEPENDENCY.NAME DEPENDENT_NAME FROM V$RESULT_CACHE_OBJECTS RCO
JOIN V$RESULT_CACHE_DEPENDENCY RCD
ON RCD.RESULT_ID = RCO.ID
JOIN V$RESULT_CACHE_OBJECTS RCO_DEPENDENCY
ON RCD.DEPEND_ID = RCO_DEPENDENCY.ID;  

TYPE       STATUS    NAME                                                         CACHE_ID                       CACHE_KEY                      DEPENDENT_ DEPENDENT DEPENDENT_NAME
---------- --------- ------------------------------------------------------------ ------------------------------ ------------------------------ ---------- --------- --------------------
Result     Published "SYS"."EMPNAME"::8."EMPNAME"#762ba075453b8b0d #1             08zynh929vwk261u11pq64h9zu     62cu7kudwm3xma8zch8avz3ndu     Dependency Published SYS.EMPNAME
Result     Published "SYS"."EMPNAME"::8."EMPNAME"#762ba075453b8b0d #1             08zynh929vwk261u11pq64h9zu     33z0nabqbda80cgcsudkvpm005     Dependency Published SYS.EMPNAME
Result     Published "SYS"."EMPNAME"::8."EMPNAME"#762ba075453b8b0d #1             08zynh929vwk261u11pq64h9zu     62cu7kudwm3xma8zch8avz3ndu     Dependency Published SCOTT.EMP
Result     Published "SYS"."EMPNAME"::8."EMPNAME"#762ba075453b8b0d #1             08zynh929vwk261u11pq64h9zu     33z0nabqbda80cgcsudkvpm005     Dependency Published SCOTT.EMP

4 rows selected.

适用场景

  • 函数频繁调用;
  • 函数依赖对象的数据不经常变化;
  • 函数返回的结果集较小;

适用限制

PL/SQL function result cache 不适用于以下情况:

  • 函数是在具有调用者权限的模块中或匿名块中定义的;
  • 函数包含OUT 或IN OUT 参数;
  • 函数包含下列类型的IN 参数:BLOB、CLOB、NCLOB、REF CURSOR、集合、对象或记录;
  • 函数的返回类型为:BLOB、CLOB、NCLOB、REFCURSOR、对象、记录或包含上述不受支持的某个返回类型的集合;
  • 函数在执行过程中除了数据查询外,还需要对数据进行更改或需要进行其他操作,如调用系统函数等;
  • 函数依赖特定于会话的特定设置;

相关数据字典

(G)V$RESULT_CACHE_STATISTICS : 各种高速缓存设置和内存使用量统计信息
(G)V$RESULT_CACHE_MEMORY : 所有内存块和相应的统计信息
(G)V$RESULT_CACHE_OBJECTS: 所有对象(高速缓存结果和依赖性)及其属性
(G)V$RESULT_CACHE_DEPENDENCY: 高速缓存结果之间的依赖性详细信息及依赖性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值