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