直接加RESULT_CACHE可缓存函数结果,但须满足确定性、无副作用、仅IN参数且类型受限等条件;定义时需在RETURN后紧接RESULT_CACHE,依赖表DML自动失效缓存。

直接加 RESULT_CACHE 就能缓存函数结果,但必须满足确定性、无副作用、参数类型受限等硬性条件,否则编译报错或运行时失效。
函数定义必须显式声明 RESULT_CACHE 关键字
不是在调用时加 hint,而是在 CREATE OR REPLACE FUNCTION 语句的返回类型后紧跟 RESULT_CACHE(11gR2 起可省略 RELIES_ON):
CREATE OR REPLACE FUNCTION get_dept_name(p_dept_id NUMBER) RETURN VARCHAR2 RESULT_CACHE IS l_name VARCHAR2(100); BEGIN SELECT department_name INTO l_name FROM departments WHERE department_id = p_dept_id; RETURN l_name; END;
-
RESULT_CACHE必须紧接在返回类型之后、AS 或 IS 之前 - 11gR1 需额外写
RESULT_CACHE RELIES_ON (departments),R2+ 自动推断依赖关系 - 函数重建(
CREATE OR REPLACE)会自动使旧缓存失效,无需手动清理
函数必须满足确定性(DETERMINISTIC)且无副作用
Oracle 不强制要求写 DETERMINISTIC,但若函数实际不满足该语义(如内部调用 SYSDATE、修改包变量、查临时表),缓存可能返回错误结果或被静默跳过:
- 禁止使用
OUT/IN OUT参数;只允许IN参数 - 禁止参数为
LOB、REF CURSOR、COLLECTION、OBJECT、RECORD类型 - 函数体中不能有 DML、DDL、提交/回滚、
DBMS_OUTPUT、包状态变更等副作用 - 若逻辑上每次输入相同就输出相同,建议显式加上
DETERMINISTIC,增强可读性和 Oracle 优化器信任度
缓存失效由底层表 DML 自动触发,但依赖粒度是表级
只要对函数查询所依赖的任意基表(如上面的 departments)执行 INSERT/UPDATE/DELETE 或 GRANT,所有缓存结果立即置为 INVALID,下次调用重新执行并缓存:
- 失效不是行级或块级,哪怕只改一行,整张表相关的所有缓存全失效
- 这意味着:高写入频率的表不适合用
RESULT_CACHE,否则缓存命中率趋近于 0 - 适合场景:组织机构、省市编码、产品分类等几乎只读的维表
- 可通过
v$result_cache_objects查看当前缓存对象及其STATUS(Published表示可用,Invalid表示已失效)
监控与调试:别只看“有没有缓存”,要看“有没有命中”
缓存存在 ≠ 命中生效。需结合两个视图交叉验证:
- 查统计:
SELECT name, value FROM v$result_cache_statistics WHERE name IN ('Create Count Success', 'Find Count')—— 若Find Count增长缓慢甚至为 0,说明没命中 - 查对象:
SELECT id, name, type, status, invalidations FROM v$result_cache_objects WHERE type = 'Function'—— 确认函数是否真被缓存,invalidations > 0表示已被刷过 - 常见漏掉的坑:函数里用了
USERENV('LANG')这类上下文函数,Oracle 视为非确定性,拒绝缓存(错误不报,但v$result_cache_objects里找不到该函数)
真正难的不是加关键字,而是确认函数行为是否“干净”——没有隐式依赖、没有上下文泄漏、没有跨事务状态残留。一旦缓存了错误结果,排查成本远高于不用缓存。


















