加了 result_cache 却没提速,大概率是函数根本没进缓存:因调用非确定性函数、参数非标量、查询非确定性数据源三道硬闸未通过;缓存键字节级敏感且 dml 后全表失效。

加了 RESULT_CACHE 却没提速?大概率是函数根本没进缓存,不是性能问题,而是配置或写法不合规。
为什么你的 PL/SQL 函数没走缓存
Oracle 对 RESULT_CACHE 的执行有三道硬闸,任一不满足就直接跳过缓存,连尝试都不做:
- 函数体里调用了非确定性函数,比如
SYSDATE、USER、DBMS_RANDOM.VALUE、SEQ.NEXTVAL,哪怕只有一行也会拒之门外 - 参数类型不是标量:传入
REF CURSOR、RECORD、自定义对象或集合类型,缓存键无法生成,直接报ORA-06553: PLS-306 - 函数内部查询了带触发器、物化视图日志、或含
ROWNUM/ORDER BY(无确定性排序)的表——这些都被 Oracle 视为“非确定性数据源”
怎么验证缓存是否真生效
别信执行计划,它不显示 RESULT_CACHE 是否命中。必须靠运行时行为 + 系统视图交叉验证:
- 第一次调用后查
V$RESULT_CACHE_OBJECTS:找到对应函数条目,且STATUS = 'Published'才算成功注册 - 连续两次相同参数调用,观察
V$SQL中该 SQL 的EXECUTIONS字段——第二次应仍为 1(说明没重跑 SQL) - 在函数体开头加
DBMS_OUTPUT.PUT_LINE('executed'):如果第二次还打印,说明完全没走缓存,立刻回查上一条限制项
缓存键敏感到字节级,类型/精度错一点就失效
RESULT_CACHE 的缓存键是按参数值的**原始字节表示**生成的,不是语义等价匹配:
-
get_name(p_id IN NUMBER)接收'123'(VARCHAR2)会报错;但接收123(NUMBER)或TO_NUMBER('123')可以 -
NUMBER(10)和NUMBER(10,0)被视为两个不同键,缓存不共享 - 绑定变量传参时,调用方声明的变量类型必须与函数参数定义**完全一致**,不能依赖 PL/SQL 隐式转换
DML 后缓存全失效,高写场景慎用
RESULT_CACHE 的失效粒度是表级,不是行级或结果级:
- 函数里查了
config_table和status_ref两张表,只要其中任意一张被INSERT/UPDATE/DELETE,所有缓存条目立刻清空 - 没有“局部刷新”机制——改一行,全刷掉;哪怕只更新了无关字段,缓存照样失效
- 如果底层表每分钟都有 DML,缓存命中率会趋近于 0,此时开启反而增加哈希键计算开销,建议关掉
真正适合 RESULT_CACHE 的函数,背后只查极少变动的码表(如 country_codes、currency_types),或纯计算逻辑(不查表)。一旦涉及业务表或频繁更新的配置,不如用应用层缓存或物化视图。











