Если вы используете ссылку на базу данных, можно создать кэш результатов функции, который будет читать из таблицы при изменении параметра, но не будет аннулирован при изменении таблицы.
Очевидно, есть некоторые проблемы с этим подходом; производительность (даже для самостоятельной ссылки), обслуживание, функция может возвращать неверный результат, все ненавидят ссылки на базы данных и т. д.
Обратите внимание, что RELIES_ON устарела в 11gR2. Зависимости автоматически определяются во время выполнения, даже динамический SQL здесь вам не поможет. Но, очевидно, это отслеживание зависимостей не работает над ссылками базы данных.
Сценарий ниже демонстрирует, как это работает. Удалите «@myself» из функции, чтобы увидеть, как она обычно работает. Часть кода основана на этой замечательной статье .
--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;