【问题标题】:Empty RELIES_ON for RESULT_CACHE为 RESULT_CACHE 清空 RELIES_ON
【发布时间】:2011-04-29 01:02:10
【问题描述】:

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

所以当表发生变化时——我的缓存失效了,函数又被执行了。

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

有可能(不用动态sql)吗?

【问题讨论】:

    标签: oracle oracle11g oracle11gr2


    【解决方案1】:

    仅依赖于其参数的函数可以声明为 DETERMINISTIC。此函数的结果在某些情况下会被缓存。这个thread on the OTN forums 展示了确定性函数结果如何缓存在 SQL 语句中。

    从 10gR2 开始,函数结果不会跨 SQL 语句缓存,也不会缓存在 PL/SQL 中。不过,如果您在 SELECT 中调用可能会被调用很多时间的函数,此缓存功能仍然很有用。

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

    【讨论】:

    • 是的,我试图将 RELIES_ON 指定给另一个表,但 oracle 足够聪明,可以看出我在作弊 :-S 好吧,DETERMINISTIC 看起来正是我想要的。将在我的下一个工作日检查它。谢谢。
    【解决方案2】:

    正确答案是否定的。 在结果缓存和物化视图等由于失效或开销过多而无法工作的情况下,Oracle In-Memory Database Cache 选项是一种解决方案。见result caches ..... what about heavily modified data 这是一个真正聪明的选择,不便宜。

    【讨论】:

      【解决方案3】:

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

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

      请注意,RELIES_ON 在 11gR2 中已弃用。依赖关系是在运行时自动确定的,即使是动态 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;
      

      【讨论】:

        【解决方案4】:

        两种选择:

        1. 不查询任何表。

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

        【讨论】:

        • 好吧,作为一个 9k 用户,您应该明白这不是一个答案 ;-) 我希望回答一些将行为更改为所需选项的选项,或者只是“否”。 (无论如何,+1 用于编写替代方案(虽然我不喜欢))
        • @zerkms 那里有很好的嵌套括号:)
        • 好吧,作为 22k 用户,您应该明白,在这种情况下,“否”并不是严格意义上的正确答案...... :) - 另外,我认为这个答案可能对来访的人有所帮助以后再说。
        • @Jeffrey Kemp:呵呵,好的;-)(顺便说一句,“不”仍然是一个很好的答案,至少我认为是这样)
        • 嗯,不是真的——你问“是否有可能实现一个只依赖于输入参数的函数”,答案是肯定的 :)
        猜你喜欢
        • 1970-01-01
        • 2021-06-22
        • 2011-10-17
        • 2016-12-19
        • 2016-09-11
        • 1970-01-01
        • 2014-08-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多