4

手順に問題があります。「大きな」セット (800 以上の親、1300 以上の子) に対して実行すると、非常に遅くなります (30 ~ 60 秒)。

基本的な考え方は、特定の検索基準に適合するすべての親レコード (およびそれぞれの子レコード) と、計算する必要がある 3 つの追加情報を取得することです。

問題に対する私のアプローチは

  1. 計算値用の追加フィールドを持つカスタム レコード タイプを作成します。
  2. このレコード タイプへの参照は、メイン処理関数によって制御される各関数に渡すことができます。
  3. 親レコードごとに値が計算されるので、それをレコードに追加します。

各プロシージャGET_PARENT_RECORDSGET_CHILD_RECORDSは検索ごとに 1 回呼び出され、各計算関数は N 回実行されます (N は親レコードまたは子レコードの数です)。


質問 1 : これは正しいアプローチですか? (弱く型付けされたカーソル、パイプライン化された関数) そうでない場合、やり直すことができると仮定して、どのように問題に取り組むべきでしたか?

質問 2 : 完全な書き直しを除いて、提供されたコードで明らかに改善できる点はありますか?

質問 3 : または、プロシージャを数回実行したときに、同じ遅いクエリが 20 秒で返されたことに気付いたので、何か他のことが間違っている可能性がありますか?


パッケージ定義

create or replace
PACKAGE THIS_PKG AS

  Type parentCursor IS REF CURSOR;
  Type childCursor IS REF CURSOR;

  Type ParentRecordType IS RECORD (
    other_columns,
    Extra_column_A,
    Extra_column_B, 
    Extra_column_C,
    Row_num);    

  --associative array
  TYPE ParentArray IS TABLE OF ParentRecordType;

  FUNCTION processParents(
      p IN THIS_PKG. parentCursor
  )  RETURN ParentArray
  PIPELINED
  ;

  FUNCTION countSomething(some params…)
      RETURN INT;

  FUNCTION checkCondX (SomeParent IN ParentRecordType) 
      RETURN VARCHAR2;

  FUNCTION checkCondY (SomeParent IN ParentRecordType)
      RETURN VARCHAR2;

  PROCEDURE GET_PARENT_RECORDS( other_parameters, Parents OUT THIS_PKG.parentCursor);

  PROCEDURE GET_CHILD_RECORDS( other_parameters, Children OUT THIS_PKG.childCursor);

END THIS_PKG;

パッケージ本体

-- omitted

FUNCTION processParents(
      p IN THIS_PKG.parentCursor
  )  RETURN ParentArray
  PIPELINED
  IS
      out_rec  ParentArray;
      someParent   ParentRecordType;
  BEGIN
    LOOP
        FETCH p BULK COLLECT INTO out_rec LIMIT 100;

        FOR i IN 1 .. out_rec.COUNT
        LOOP
        out_rec(i).extra_column_A := countSomething (out_rec(i).field1, out_rec(i).field2);
        out_rec(i).extra_column_B := checkCondX(out_rec(i));
        out_rec(i).extra_column_C := checkCondY(out_rec(i));
        pipe row(out_rec(i));
        END LOOP;

        EXIT WHEN p%NOTFOUND;
    END LOOP;
    RETURN;
  END processParents;

PROCEDURE GET_PARENT_RECORDS(
      some_columns,
      Parents OUT THIS_PKG. parentCursor) IS
  BEGIN   
      OPEN Parents FOR
      SELECT *
      FROM TABLE(processParents (CURSOR(
        SELECT *
        FROM (
              --some select statement with quite a few where clause 
          --to simulate dynamic search (from pre-canned search options)
       )
     ))) abc
      WHERE abc.extra_column_C like '%xyz%' --(xyz is a user given value)
      ;
END GET_PARENT_RECORDS;

更新 昨日、調査を行ったところ、(Toad の) Quest Batch SQL Optimizer に出会いました。パッケージを差し込んで、これが私が得たものです。

バッチ オプティマイザーの結果 バッチ オプティマイザーの結果

複雑なクエリ 複雑なクエリ

問題のあるクエリ 問題のあるクエリ

4

2 に答える 2

0

Quest Batch SQL Optimizer (Toad 製) またはその他のツールは、関数内で何を行っているかを理解していないことを考慮すると、役に立ちません。問題は「FETCH p BULK COLLECT INTO out_rec LIMIT 100;」にあります。p に渡されるクエリの品質によって、最終的な実行計画と実行時間が実際に定義されます。パイプライン処理は速度低下の原因ではありません。プロシージャを数回実行すると、Oracle はキャッシュされたデータを使用します。私の最善のアドバイスは、この特定の目的のために PL/SQL の代わりに Java を使用すると、理解がより簡単になるということです。

于 2013-12-23T16:25:57.357 に答える