RESULT_CACHE 的 RELIES_ON 为空

发布于 2024-11-03 16:24:28 字数 156 浏览 7 评论 0原文

我在函数内部有一个 RESULT_CACHE 查询。

因此,当表更改时 - 我的缓存将失效并且函数将再次执行。

我想要的是实现依赖于输入参数的函数,而不依赖于任何隐式依赖项(如表等)。

有可能吗(没有动态sql)?

I have a query inside the function with RESULT_CACHE.

So when the table is changed - my cache is invalidated and function is executed again.

What I want is to implement the function that depends only on input parameters, and doesn't depend on any implicit dependencies (like tables, etc).

Is it possible (without dynamic sql)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

苦妄 2024-11-10 16:24:28

仅依赖于其参数的函数可以声明为 DETERMINISTIC。在某些情况下,该函数的结果将被缓存。此OTN 论坛上的帖子展示了如何在 SQL 中缓存确定性函数结果声明。

从 10gR2 开始,函数结果不会跨 SQL 语句进行缓存,也不会在 PL/SQL 中缓存。不过,如果您在 SELECT 中调用某个函数(该函数可能会被多次调用),则此缓存功能仍然很有用。

我现在没有可用的 11gR2 实例,因此我无法测试 RESULT_CACHE 功能,但是您是否考虑过依赖于固定虚拟表(例如永远不会更新的表)来声明您的函数?

a function that depends only on its parameters can be declared DETERMINISTIC. The results of this function will be cached in some cases. This thread on the OTN forums shows how deterministic function results get cached inside SQL statements.

As of 10gR2, the function results don't get cached across SQL statements nor do they get cached in PL/SQL. Still, this cache feature can be useful if you call a function in a SELECT where it might get called lots of time.

I don't have a 11gR2 instance available right now, so I can't test the RESULT_CACHE feature, but have you considered delaring your function relying on a fixed dummy table (a table that never gets updated for instance)?

窗影残 2024-11-10 16:24:28

正确答案是否定的。
当结果缓存和物化视图等由于失效或开销太大而无法工作时,一个解决方案是 Oracle 内存数据库缓存选项。请参阅 结果缓存 ..... 严重修改的数据怎么样 这是一个真正明智的选择,但并不便宜。

The correct answer is NO.
A solution in cases where things like result caches and materialized views won't work because of invalidations or too much overhead is the Oracle In-Memory Database Cache option. See result caches ..... what about heavily modified data It's a real smart option, not cheap.

木緿 2024-11-10 16:24:28

如果使用数据库链接,则可以创建一个函数结果缓存,该缓存将在参数更改时从表中读取,但不会在表更改时失效。

显然,这种方法存在一些问题;性能(即使是自链接)、维护、函数可能返回错误结果、每个人都讨厌数据库链接等。

请注意,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;

If you use a database link it is possible to create a function result cache that will read from a table when a parameter changes but will not be invalidated when the table changes.

Obviously there are some issues with this approach; performance (even for a self-link), maintenance, the function may return the wrong result, everybody hates database links, etc.

Note that RELIES_ON is deprecated in 11gR2. Dependencies are automatically determined at run-time, even dynamic SQL wouldn't help you here. But apparently this dependency tracking doesn't work over database links.

The script below demonstrates how this works. Remove "@myself" from the function to see how it normally works. Some of the code is based on 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;
少年亿悲伤 2024-11-10 16:24:28

两个选项:

  1. 不查询任何表。

  2. 实现您自己的缓存 - 将函数包装在包中,并将查询结果存储在内存中的 PL/SQL 表中。然而,这种方法的缺点是缓存只能在单个会话中工作。每个会话都会维护自己的缓存。

Two options:

  1. Don't query any table.

  2. Implement your own cache - wrap the function in a package, and store the query results in a PL/SQL table in memory. The downside to this approach, however, is that the cache only works within a single session. Each session will maintain its own cache.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文