set serveroutput on;
declare
l_emp_id NUMBER;
begin
l_emp_id := 99;
IF is_manager(p_emp_id => l_emp_id) THEN
DBMS_OUTPUT.PUT_LINE('I am a manager.');
ELSE
DBMS_OUTPUT.PUT_LINE('I am not a manager.');
END IF;
end;
执行完后的输出结果为
anonymous block completed Manager status confirmation in progress. I am not a manager.
执行完后,让我们回头看看 Oracle的字典表吧
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
我们能看到Oracle缓存了一个结果集,这个存储结果的依赖对象是Departments表和 Is_manager 函数本身。也就是这两个对象中任何一个发生变化,Oracle都会将对应的Function Result Cache 设置为无效。
当同一个函数被Oracle Instance 上的不同Session执行时,如果传入的参数值完全相同,Oracle将试图从缓存中直接获得结果。这意味着对于函数 的Cache Result,不同的参数值组合将对应不同的结果集。我们试着执行上面的函数两次,第一次的输入参数为l_emp_id := 99; ,那么第二次的输入参数为l_emp_id := 100;那Oracle 会缓存两份返回结果, 这两份结果的依赖对象是一样的。
RELIES_ON 子句
我们看到Oracle的依赖管理已经很好的为我们找到了某个缓存的函数结果集所依赖的底层对象。但当一个函数变得复杂的时候,即使Oracle能够帮我们维护这种依赖关系,那也是费老劲了。一个比较简单的方式是我们显示地指明某个函数所依赖的对象。这个关键字就是RELIES_ON 子句。
create or replace
function is_manager (p_emp_id IN employees.employee_id%TYPE)
RETURN BOOLEAN
RESULT_CACHE RELIES_ON (departments)
IS
manager_count NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE('Manager status confirmation in progress.');
SELECT COUNT(1)
INTO manager_count
FROM departments
WHERE MANAGER_ID = p_emp_id;
IF manager_count > 0 THEN
RETURN (TRUE);
ELSE
RETURN (FALSE);
END IF;
END is_manager;
应用场景
数据库使用频繁的函数,并且这些函数所依赖的数据很少发生变化。同时,函数本身不能具备如下条件的情况下
当函数使用Invoker rights ( 使用调用该函数的用户权限执行) 方式执行时(通过AUTHID子句实现)。默认情况下,函数的执行方式为Definer rights (使用定义该函数的用户权限执行)。函数有OUT 或IN OUT 参数时函数的IN 参数是BLOB, Collection, Object 或Record 时函数的RETURN 的数据类型是BLOB,Ref Cursor,Object,或者是任何上述类型的集合。注意事项
在决定一个函数是否需要被缓存前,请检查一下下面几个注意事项。 当函数在执行过程中对数据进行更改时不适用。如果这种函数被缓存,后续的任何函数调用都不再执行,很显然这时候你的数据更新操作就不会发生了。当函数除数据查询外,还做了诸如调用 系统函数,如UTL_MAIL(),以完成一些特定功能的时不适用。当函数执行过程中使用了一些Session级别的默认设置时,不使用。例如调用TO_CHAR函数对日期类型进行格式转换,如果没有指定目标转换格式的话,那将用Session 的 NLS_DATE_FORMAT参数的设定。因为Function Result Cache是跨 Session共享的,所以一旦缓存,某个Session可能会得到错误的返回结果。总结
除了Oracle Server Result Cache 外,Oracle 还提供了Oracle Client Result Cache. 这个功能主要是将结果集缓存在客户端的内存,而不是Server端。如果有兴趣,可参阅Oracle相关文档。我个人用的不多。