RESULT_CACHE未生效主要因三处硬性限制:一是函数内含非确定性操作(如SYSDATE、触发器表等);二是参数非标量类型或调用非DETERMINISTIC函数;三是缓存键对类型/精度敏感,隐式转换导致键不匹配。
RESULT_CACHE 为什么没生效?检查这三处硬性限制
pl/sql 函数加了 result_cache 却没走缓存,大概率是撞上了 oracle 的强制约束。它不是“加了就缓”——函数体内不能出现任何会破坏确定性的操作。
-
SELECT语句必须只查DETERMINISTIC表(即无触发器、无物化视图日志、不涉及SYSDATE/USER/DBMS_RANDOM等非确定性函数) - 函数参数类型必须是标量(
VARCHAR2、NUMBER、DATE),不能是REF CURSOR、RECORD或对象类型 - 函数体里不能调用任何非
DETERMINISTIC函数,包括你自己写的没加DETERMINISTIC关键字的函数
怎么验证缓存是否真的命中?别信执行计划
执行计划里看不到 RESULT_CACHE 是否起效,得靠实际运行时行为和系统视图交叉验证。
- 第一次调用后查
V$RESULT_CACHE_OBJECTS:有对应条目且STATUS = 'Published'才算缓存成功 - 连续两次相同参数调用,看
V$SQL中对应 SQL 的EXECUTIONS增长是否为 1(第二次应跳过 SQL 执行) - 在函数里加
DBMS_OUTPUT.PUT_LINE('executed')—— 如果第二次还打印,说明根本没走缓存,立刻回头检查上一条的限制项
RESULT_CACHE 和函数参数绑定太敏感,小心隐式转换
缓存键(cache key)是按参数值的**字节级表示**生成的,哪怕语义相同,类型或精度不同就会分两个缓存槽。
- 传入
NUMBER(10)和NUMBER(10,0)被视为不同键 -
'123'(VARCHAR2)和123(NUMBER)绝对不共享缓存 - 调用方用绑定变量传参时,确保变量声明类型与函数参数完全一致,别依赖 PL/SQL 自动转换
示例:函数定义为 FUNCTION get_name(p_id IN NUMBER) RETURN VARCHAR2 RESULT_CACHE,调用时用 get_name(123) 和 get_name(TO_NUMBER('123')) 是安全的;但用 get_name('123') 就会失败(类型不匹配,报 ORA-06553: PLS-306)。
缓存失效比你想的更频繁,尤其在 DML 后
RESULT_CACHE 不是独立内存池,它和底层表强耦合。只要函数里查的任意一张表发生 DML(哪怕只是另一会话做的 INSERT),整个函数的所有缓存项立刻失效。
- 没有细粒度失效机制——改一行,全刷掉
- 如果函数查多张表,其中一张被 DML,全部缓存清空
- 高并发写场景下,缓存命中率可能趋近于 0,这时不如关掉,避免额外的哈希键计算开销
真正适合 RESULT_CACHE 的函数,是那些背后查的是极少变动的配置表、码表,或者纯计算型(无 SQL)函数。业务主表上的查询,基本别指望它稳住。











