3

テーブルを返すパイプライン関数を作成しました。この関数を別の関数の動的ビューのようにwith句で使用して、特定のレコードをマークします。次に、さまざまな基準に基づいて、このクエリの結果を集計クエリで使用します。私がやりたいのはunion all、これらの集計を一緒にすることです (それらはすべて同じソース データを使用しますが、異なる階層レベルで集計を表示するため)。

個々のレベルのデータを生成すると、正常に機能します。ただし、それらを結合しようとすると、ORA-12840 エラーが発生しますcannot access a remote table after parallel/insert direct load txn

(私の関数とクエリは、DB リンクを介してリモート サーバー上のテーブルを見ていることに注意してください)。

ここで何が起こっているのですか?


コードのアイデアは次のとおりです。

function getMatches(criteria in varchar2) return myTableType pipelined;

...ここで、この関数は基本的に、リモートテーブルを参照カーソルとして参照する動的 SQL を実行し、結果を吐き出します。

次に、ファクタリングされたクエリは次のようになります。

with marked as (
  select id from table(getMatches('OK'))
),
fullStats as (
  select    mainTable.id,
            avg(nvl2(marked.id, 1, 0)) isMarked,
            sum(mainTable.val) total
  from      mainTable
  left join marked
  on        marked.id = mainTable.id
  group by  mainTable.id
)

最初の要因の理由は速度です-インライン化すると、結合でクエリが非常に遅くなります-しかし、いずれにしても、例外の原因となっているもののステータスは変更されません.

次に、完全な概要については、次のようにします。

select sum(total) grandTotal
from   fullStats

...または概要については、次のisMarkedとおりです。

select sum(total) grandTotal
from   fullStats
where  isMarked = 1

これらは個別にうまく動作します(私の疑似コードは間違っているか単純すぎるかもしれませんが、あなたはそれを理解しています)が、union allそれらを一緒にするとすぐにORA-12840エラーが発生します:(


編集リクエストにより、ここに私の関数の難読化されたバージョンがあります:

function getMatches(
    search in varchar2)
  return idTable pipelined
  as
    idRegex     varchar2(20) := '(05|10|20|32)\d{3}';
    searchSQL   varchar2(32767);

    type rc is ref cursor;
    cCluster rc;
    rCluster idTrinity;

    BAD_CLUSTER exception;
  begin
    if regexp_like(search, '^L\d{3}$') then
      searchSQL := 'select distinct null id1, id2_link id2, id3_link id3 from anotherSchema.linkTable@my.remote.link where id2 = ''' || search || '''';    
    elsif regexp_like(search, '^' || idRegex || '(,' || idRegex || || ')*$') then
      searchSQL := 'select distinct null id1, id2, id3 from anotherSchema.idTable@my.remote.link where id2 in (' || regexp_replace(search, '(\d{5})', '''\1''') || ')';
    else
      raise BAD_CLUSTER;
    end if;

    open cCluster for searchSQL;
    loop
      fetch cCluster into rCluster;
      exit when cCluster%NOTFOUND;

      pipe row(rCluster);
    end loop;

    close cCluster;
    return;

  exception
    when BAD_CLUSTER then
      raise_application_error(-20000, 'Invalid Cluster Search');
      return;
    when others then
      raise_application_error(-20999, 'API' || sqlcode || chr(10) || sqlerrm);
      return;
  end getMatches;

これは非常にシンプルで、データベースへのアクセスが制限された API 向けに設計されており、洗練されています (したがって、コンマ区切りの文字列を有効な引数として渡すことができます): グループ化コードを指定すると、リンクされた ID が返されます (複合 ID -フィールドキー); ただし、コードのカスタム リストを指定すると、代わりにそれらが返されます。

私は Oracle 10gR2 を使用しています。どのバージョンか正確にはわかりませんが、オフィスに戻ったら調べることができます :P

4

1 に答える 1

2

正直なところ、問題の原因はわかりませんが、それを解決する最も簡単な方法は、一時テーブルを作成し、パイプライン関数からの値を入力して、WITH 句内でテーブルを使用することです。確かに一時テーブルを作成する必要がありますが、動的サンプリングはトリックなしでパイプライン関数に適用されないため、パフォーマンスが大幅に変化することは間違いありません。

ps 問題は as ( select /*+ INLINE / id from table(getMatches('OK'))) とマークすることで修正できますが、確かにそれはあなたが探しているものではないので、私の提案は WITH が何かを行うことが確認されています「/ + APPEND*/」をその中に挿入する」のように。

于 2012-08-20T16:52:14.937 に答える