我在函数内部有一个带有RESULT_CACHE的查询。
因此,当表格被更改时 - 我的缓存无效并再次执行功能。
我想要的是在输入参数上实现依赖 的函数,并且不依赖于任何隐式依赖(如表等)。
是否可以(没有动态sql)?
答案 0 :(得分:2)
正确答案是否定的。 在结果缓存和物化视图之类的事情由于失效或开销太大而无法工作的情况下,Oracle内存数据库缓存选项就是一种解决方案。见result caches ..... what about heavily modified data这是一个真正明智的选择,并不便宜。
答案 1 :(得分:2)
仅依赖于其参数的函数可以声明为DETERMINISTIC。在某些情况下,将缓存此函数的结果。这个thread on the OTN forums显示了确定性函数结果如何在SQL语句中缓存。
从10gR2开始,函数结果不会跨SQL语句缓存,也不会在PL / SQL中缓存。尽管如此,如果在SELECT中调用一个可能被调用很多时间的函数,这个缓存功能会很有用。
我目前没有可用的11gR2实例,所以我无法测试RESULT_CACHE功能,但您是否考虑过依赖于固定的虚拟表(例如永远不会更新的表)来声明您的功能? / p>
答案 2 :(得分:2)
如果使用数据库链接,则可以创建一个函数结果缓存,该参数缓存将在参数更改时从表中读取,但在表更改时不会失效。
显然这种方法存在一些问题;性能(即使是自我链接),维护,功能可能返回错误的结果,每个人都讨厌数据库链接等。
请注意,在11gR2中不推荐使用RELIES_ON。依赖关系是在运行时自动确定的,即使动态SQL也不会对您有所帮助。但显然这种依赖性跟踪不适用于数据库链接。
下面的脚本演示了这是如何工作的。从函数中删除“@myself”以查看它是如何正常工作的。部分代码基于this great article。
--For testing, create a package that will hold a counter.
create or replace package counter is
procedure reset;
procedure increment;
function get_counter return number;
end;
/
create or replace package body counter as
v_counter number := 0;
procedure reset is begin v_counter := 0; end;
procedure increment is begin v_counter := v_counter + 1; end;
function get_counter return number is begin return v_counter; end;
end;
/
--Create database link
create database link myself connect to <username> identified by "<password>"
using '<connect string>';
drop table test purge;
create table test(a number primary key, b varchar2(100));
insert into test values(1, 'old value1');
insert into test values(2, 'old value2');
commit;
--Cached function that references a table and keeps track of the number of executions.
drop function test_cache;
create or replace function test_cache(p_a number) return varchar2 result_cache is
v_result varchar2(100);
begin
counter.increment;
select b into v_result from test@myself where a = p_a;
return v_result;
end;
/
--Reset
begin
counter.reset;
end;
/
--Start with 0 calls
select counter.get_counter from dual;
--First result is "value 1", is only called once no matter how many times it runs.
select test_cache(1) from dual;
select test_cache(1) from dual;
select test_cache(1) from dual;
select counter.get_counter from dual;
--Call for another parameter, counter only increments by 1.
select test_cache(2) from dual;
select test_cache(2) from dual;
select test_cache(2) from dual;
select counter.get_counter from dual;
--Now change the table. This normally would invalidate the cache.
update test set b = 'new value1' where a = 1;
update test set b = 'new value2' where a = 2;
commit;
--Table was changed, but old values are still used. Counter was not incremented.
select test_cache(1) from dual;
select test_cache(2) from dual;
select counter.get_counter from dual;
--The function is not dependent on the table.
SELECT ro.id AS result_cache_id
, ro.name AS result_name
, do.object_name
FROM v$result_cache_objects ro
, v$result_cache_dependency rd
, dba_objects do
WHERE ro.id = rd.result_id
AND rd.object_no = do.object_id;
答案 3 :(得分:1)
两个选项:
不要查询任何表格。
实现自己的缓存 - 将函数包装在一个包中,并将查询结果存储在内存中的PL / SQL表中。然而,这种方法的缺点是缓存只能在单个会话中工作。每个会话都将保留自己的缓存。