Пустой RELIES_ON для RESULT_CACHE

У меня есть запрос внутри функции с RESULT_CACHE.

Поэтому, когда таблица изменяется, мой кеш становится недействительным, и функция выполняется снова.

Я хочу реализовать функцию, которая зависит только от входных параметров и не зависит ни от каких неявных зависимостей (таких как таблицы и т. д.).

Возможно ли (без динамического sql)?


person zerkms    schedule 29.04.2011    source источник


Ответы (4)


функция, зависящая только от своих параметров, может быть объявлена ​​DETERMINISTIC. В некоторых случаях результаты этой функции будут кэшироваться. В этой теме на форумах OTN показано, как результаты детерминированных функций кэшируются внутри SQL. заявления.

Начиная с версии 10gR2, результаты функции не кэшируются в операторах SQL и не кэшируются в PL/SQL. Тем не менее, эта функция кеша может быть полезна, если вы вызываете функцию в SELECT, где она может вызываться много раз.

У меня сейчас нет доступного экземпляра 11gR2, поэтому я не могу протестировать функцию RESULT_CACHE, но рассматривали ли вы возможность декларирования вашей функции, опирающейся на фиксированную фиктивную таблицу (например, таблицу, которая никогда не обновляется)?

person Vincent Malgrat    schedule 29.04.2011
comment
Да, я пытался указать RELIES_ON для какой-то другой таблицы, но оракул достаточно умен, чтобы понять, что я жульничаю :-S Ну, DETERMINISTIC выглядит именно так, как я хочу. Проверю на следующий рабочий день. Спасибо. - person zerkms; 29.04.2011

Правильный ответ НЕТ. Решением в случаях, когда такие вещи, как кэширование результатов и материализованные представления, не будут работать из-за аннулирования или слишком больших накладных расходов, является вариант Oracle In-Memory Database Cache. См. кеши результатов... как насчет сильно измененных данных Это действительно умный вариант, не дешевый.

person ik_zelf    schedule 29.04.2011

Если вы используете ссылку на базу данных, можно создать кэш результатов функции, который будет считываться из таблицы при изменении параметра, но не станет недействительным при изменении таблицы.

Очевидно, что с этим подходом есть некоторые проблемы; производительность (даже для самоссылки), обслуживание, функция может вернуть неправильный результат, все ненавидят ссылки на базы данных и т. д.

Обратите внимание, что 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;
person Jon Heller    schedule 01.06.2011

Два варианта:

  1. Не запрашивайте какую-либо таблицу.

  2. Реализуйте свой собственный кеш - заверните функцию в пакет и сохраните результаты запроса в таблице PL/SQL в памяти. Однако недостатком этого подхода является то, что кеш работает только в рамках одного сеанса. Каждый сеанс будет поддерживать свой собственный кеш.

person Jeffrey Kemp    schedule 29.04.2011
comment
Ну, как пользователь 9k, вы должны понимать, что это не ответ ;-) Я ожидаю в качестве ответа какой-то вариант, который меняет поведение на нужное, или просто Нет (в любом случае +1 за написание альтернатив (которых я не вроде хотя)) - person zerkms; 29.04.2011
comment
@zerkms Хорошая вложенная скобка :) - person alex; 29.04.2011
comment
Что ж, как пользователь 22k, вы должны понимать, что в данном случае «Нет» — не совсем правильный ответ... :) — плюс, я думаю, что этот ответ может быть полезен для тех, кто появится позже. - person Jeffrey Kemp; 29.04.2011
comment
@Джеффри Кемп: хе-хе, хорошо ;-) (кстати, нет - все еще хороший ответ, по крайней мере, я так думаю) - person zerkms; 29.04.2011
comment
Ну не совсем — вы спросили можно ли реализовать функцию, зависящую только от входных параметров и ответ Да :) - person Jeffrey Kemp; 29.04.2011
comment
@Jeffrey Kemp: очевидно, я спросил об этом в контексте функции RESULT_CACHE, иначе я не указал это в вопросе ;-) Возможно ли это с result_cache? Все еще да? - person zerkms; 29.04.2011
comment
Ну, RESULT_CACHE не ограничивается только запросами к таблицам, не так ли? У вас может быть кэш результата для возвращаемого результата любой функции, и он будет работать до тех пор, пока функция является детерминированной. - person Jeffrey Kemp; 29.04.2011
comment
@Jeffrey Kemp: это действительно не ограничено, но в моем вопросе я указал, что у меня есть запрос ;-) - person zerkms; 29.04.2011