関数内に RESULT_CACHE を使用したクエリがあります。
したがって、テーブルが変更されると、キャッシュが無効になり、関数が再度実行されます。
私が望むのは、入力パラメーターのみに依存し、暗黙的な依存関係 (テーブルなど) には依存しない関数を実装することです。
(動的SQLなしで)可能ですか?
関数内に RESULT_CACHE を使用したクエリがあります。
したがって、テーブルが変更されると、キャッシュが無効になり、関数が再度実行されます。
私が望むのは、入力パラメーターのみに依存し、暗黙的な依存関係 (テーブルなど) には依存しない関数を実装することです。
(動的SQLなしで)可能ですか?
パラメータのみに依存する関数は、DETERMINISTIC として宣言できます。この関数の結果は、場合によってはキャッシュされます。OTN フォーラムのこのスレッドは、決定論的関数の結果が SQL ステートメント内にキャッシュされる方法を示しています。
10gR2 の時点で、関数の結果は SQL ステートメント間でキャッシュされず、PL/SQL でもキャッシュされません。それでも、このキャッシュ機能は、長時間呼び出される可能性がある SELECT で関数を呼び出す場合に役立ちます。
現在利用可能な 11gR2 インスタンスがないため、RESULT_CACHE 機能をテストすることはできませんが、固定のダミー テーブル (たとえば更新されないテーブル) に依存して関数を遅延させることを検討しましたか?
正解はNOです。無効化やオーバーヘッドが大きすぎるために結果キャッシュやマテリアライズド ビューなどが機能しない場合のソリューションは、Oracle In-Memory Database Cache オプションです。結果キャッシュを参照してください..... 大幅に変更されたデータはどうですか? これは非常にスマートなオプションであり、安くはありません。
データベース リンクを使用すると、パラメータが変更されたときにテーブルから読み取られ、テーブルが変更されても無効にされない関数結果キャッシュを作成できます。
明らかに、このアプローチにはいくつかの問題があります。パフォーマンス (自己リンクの場合でも)、メンテナンス、関数が間違った結果を返す可能性がある、誰もがデータベース リンクを嫌う、など。
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;
2 つのオプション:
どのテーブルにもクエリを実行しないでください。
独自のキャッシュを実装します。関数をパッケージにラップし、クエリ結果をメモリ内の PL/SQL テーブルに格納します。ただし、このアプローチの欠点は、キャッシュが単一のセッション内でしか機能しないことです。各セッションは独自のキャッシュを維持します。