Oracle Empty依赖于\u作为结果\u缓存

Oracle Empty依赖于\u作为结果\u缓存,oracle,oracle11g,oracle11gr2,Oracle,Oracle11g,Oracle11gr2,我在带有RESULT_CACHE的函数中有一个查询 所以,当表被更改时,我的缓存将失效,函数将再次执行 我想要实现的是只依赖于输入参数的函数,而不依赖于任何隐式依赖项(如表等) 是否可能(没有动态sql)?两个选项: 不要查询任何表 实现您自己的缓存—将函数包装在包中,并将查询结果存储在内存中的PL/SQL表中。然而,这种方法的缺点是缓存只在单个会话中工作。每个会话将维护自己的缓存 正确答案是否定的。 在诸如结果缓存和物化视图之类的东西由于无效或太多开销而无法工作的情况下,一个解决方案是Orac

我在带有RESULT_CACHE的函数中有一个查询

所以,当表被更改时,我的缓存将失效,函数将再次执行

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

是否可能(没有动态sql)?

两个选项:

  • 不要查询任何表

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

  • 正确答案是否定的。
    在诸如结果缓存和物化视图之类的东西由于无效或太多开销而无法工作的情况下,一个解决方案是Oracle内存中数据库缓存选项。看,这是一个真正的智能选择,不便宜。

    一个只依赖于其参数的函数可以声明为确定性的。在某些情况下,此函数的结果将被缓存。这显示了如何在SQL语句中缓存确定性函数结果

    从10gR2开始,函数结果不会跨SQL语句缓存,也不会缓存在PL/SQL中。尽管如此,如果您在SELECT中调用函数,并且该函数可能会在很多时候被调用,那么该缓存功能仍然很有用


    我现在没有11gR2实例可用,所以我无法测试RESULT\u CACHE特性,但是您是否考虑过依赖固定的虚拟表(例如,一个永远不会更新的表)来删除函数?

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

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

    请注意,11gR2中不推荐使用依赖。依赖关系在运行时自动确定,即使动态SQL在这里也帮不上忙。但显然,这种依赖项跟踪在数据库链接上不起作用

    下面的脚本演示了这是如何工作的。从函数中删除“@imf”以查看其正常工作情况。一些代码是基于

    --对于测试,创建一个包含计数器的包。
    创建或替换程序包计数器是无效的
    程序复位;
    程序增量;
    函数获取计数器返回编号;
    结束;
    /
    根据需要创建或替换包体计数器
    v_计数器编号:=0;
    程序复位为开始v_计数器:=0;结束;
    程序增量为开始v_计数器:=v_计数器+1;结束;
    函数get_counter return number是begin return v_counter;结束;
    结束;
    /
    --创建数据库链接
    创建由“”标识的连接到的数据库链接
    使用“”;
    跌落试验台吹扫;
    创建表测试(一个数字主键,b varchar2(100));
    插入测试值(1,‘旧值1’);
    插入测试值(2,‘旧值2’);
    犯罪
    --引用表并跟踪执行次数的缓存函数。
    丢弃功能测试\u缓存;
    创建或替换函数测试\u缓存(p\u a编号)返回varchar2结果\u缓存为
    v_结果varchar2(100);
    开始
    反增量;
    从中选择b进入v_结果test@myself式中a=p_a;
    返回v_结果;
    结束;
    /
    --重置
    开始
    计数器复位;
    结束;
    /
    --从0个电话开始
    选择counter.get_counter from dual;
    --第一个结果是“值1”,无论运行多少次,都只调用一次。
    从dual中选择test_cache(1);
    从dual中选择test_cache(1);
    从dual中选择test_cache(1);
    选择counter.get_counter from dual;
    --调用另一个参数,计数器仅递增1。
    从dual中选择test_cache(2);
    从dual中选择test_cache(2);
    从dual中选择test_cache(2);
    选择counter.get_counter from dual;
    --现在换张桌子。这通常会使缓存无效。
    更新测试集b=‘新值1’,其中a=1;
    更新测试集b=‘新值2’,其中a=2;
    犯罪
    --表已更改,但仍使用旧值。计数器未递增。
    从dual中选择test_cache(1);
    从dual中选择test_cache(2);
    选择counter.get_counter from dual;
    --该函数不依赖于表。
    选择ro.id作为结果\u缓存\u id
    ,ro.name作为结果_name
    ,do.object\u name
    从v$result\u cache\u对象
    ,v$result\u cache\u dependency rd
    ,dba_对象做什么
    其中ro.id=rd.result\u id
    和rd.object_no=do.object_id;
    
    作为9k用户,您应该明白这不是答案;-)我希望答案是将行为改变为所需的行为,或者干脆说“不”。(无论如何,+1用于编写备选方案(尽管我不喜欢))@zerkms很好的嵌套括号:)作为一个22k用户,您应该明白,在这种情况下,“No”并不是严格意义上的正确答案……:)-另外,我认为这个答案可能会对后来出现的人有所帮助。@Jeffrey Kemp:呵呵,好;-)(顺便说一句,“不”仍然是一个很好的答案,至少我认为是这样)嗯,不是真的-你问“是否有可能实现一个只依赖于输入参数的函数”,答案是肯定的:)是的,我试着在另一个表中指定依赖项,但是甲骨文很聪明,知道我在作弊:-S好吧
    确定性
    看起来正是我想要的。我会在下一个工作日检查。谢谢
    
    --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;