- PR -

FETCHが遅い

投稿者投稿内容
とわき
会議室デビュー日: 2005/11/21
投稿数: 8
投稿日時: 2005-12-12 20:17
ORACLEで以下のようにカーソルとループを使って複数のテーブルからデータを取得しています。
  OPEN CUR1 FOR SQL1;
  LOOP
    FETCH CUR1 INTO REC1;
    IF CUR1%NOTFOUND THEN
      EXIT;
    END IF;
    -- 処理 --
  END LOOP;

フェッチの部分を計測したところ、最終行のフェッチが終わってから次の行をフェッチするのに
数十秒かかっていました。
ちなみに1行目から最終行までのフェッチは、1秒もかかりません。
試しに、1テーブルから取得するようにしたところ、フェッチ時間の差はありませんでした。
ということは、複数のテーブルからデータを取得するような複雑なSQLを発行するときに、
フェッチ時間の差ができる(処理時間が長くなる)ということなのでしょうか?
時間の差が出ないようにする(処理時間を短くする)方法があるのでしょうか?

何かご存知の方がいらっしゃいましたら教えてください。


[ メッセージ編集済み 編集者: とわき 編集日時 2005-12-13 09:28 ]
Anthyhime
ぬし
会議室デビュー日: 2002/09/10
投稿数: 437
投稿日時: 2005-12-13 12:24
SQLを見直すか、INDEXを作成するなどのパフォーマンスチューニングの必要があるかと思います。
とわき
会議室デビュー日: 2005/11/21
投稿数: 8
投稿日時: 2005-12-13 13:18
ご返答ありがとうございます。

確かに少し複雑なSQL文ですが、INDEXを作成してうまく使われるように作っているので、SQLPLUSで発行すると1秒かからないくらいで結果は返ってきます。

最終行の次の行のFETCHに時間がかかっているのは、どうしようもないものなのでしょうか…。
Desmo
大ベテラン
会議室デビュー日: 2004/03/24
投稿数: 149
投稿日時: 2005-12-13 14:48
> 最終行のフェッチが終わってから次の行をフェッチするするのに
> 数十秒かかっていました。

これは「最後にフェッチの処理をしてから、IF CUR1%NOTFOUND THEN でループを抜けるまでの間に数十秒かかる」って意味ですよね。
何か全件検索している臭いけど、でもSQLPlusで遅くないというのはどうしたことか。

フェッチ後の、-- 処理 -- の部分を省略しても一緒でしょうか?
それから(これはあまり意味は無いかもしれませんが)ループ文を

DECLARE
CURSOR CUR1 IS SELECT ・・・・
BEGIN
FOR REC1 IN CUR1 LOOP
-- 処理 --
 END LOOP;
END;

と変更したら変化はあるでしょうか?
とわき
会議室デビュー日: 2005/11/21
投稿数: 8
投稿日時: 2005-12-13 15:26
Desmoさん、ご返答ありがとうございます。

そうなんです。
例えば、100件取れるSELECT文だとすると、100件目(最終行)のFETCH→処理が終わって、101件目(存在しない行)のFETCHが遅いのです。

↓このロジックで計測しました(処理ロジックは入れていません)
  OPEN CUR1 FOR SQL1;
  LOOP
    DBMS_OUTPUT.PUT_LINE('FETCH前 ' || TO_CHAR(SYSDATE,'HH24:MI:SS'));
    FETCH CUR1 INTO REC1;
    DBMS_OUTPUT.PUT_LINE('FETCH前 ' || TO_CHAR(SYSDATE,'HH24:MI:SS'));
    IF CUR1%NOTFOUND THEN
      EXIT;
    END IF;
  END LOOP;

カーソルFORループでも試してみましたが、同じでした。
最後の'ループ内〜〜〜'のログで出てから数十秒後に'ループ外〜〜〜'のログが出ていました。

↓このロジックで計測しました(処理ロジックは入れていません)
 DECLARE
  CURSOR CUR1 IS SELECT 〜〜〜;
 BEGIN
  FOR REC1 IN CUR1 LOOP
   DBMS_OUTPUT.PUT_LINE('ループ内 ' || TO_CHAR(SYSDATE,'HH24:MI:SS'));
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('ループ外 ' || TO_CHAR(SYSDATE,'HH24:MI:SS'));
 END;
ZingBay
常連さん
会議室デビュー日: 2004/02/16
投稿数: 27
お住まい・勤務地: 古の奈良
投稿日時: 2005-12-13 16:35
こんにちわ。

HWMが高すぎて、EOFが返るまでのブロック読み込みに時間が掛かっているので
あれば・・・・

一旦別のテーブルにCOPYしておいて、元のテーブルをTRUNCATE TABLEし
再度データを戻してから実行したらどうなりますか?

但し、SQL*PLUSとの実行時間の違いについての検証にはなりません。
SQL*PLUSで実行した際の実行計画と、PL/SQLから実行した際の実行計画は
同一のものですか?
Anthyhime
ぬし
会議室デビュー日: 2002/09/10
投稿数: 437
投稿日時: 2005-12-13 17:05
原因を追究するのがめんどかったらBULK COLLECT INTOを利用して書き直してしまうという手もあります。
とわき
会議室デビュー日: 2005/11/21
投稿数: 8
投稿日時: 2005-12-13 20:08
ZingBayさん、Anthyhimeさん、ご返答ありがとうございます。

ZingBayさんへ
HWM、少し勉強させて頂きました。
今回3つのテーブルを結合してデータを取得しようとしているのですが、この場合もHWMが関係してくるのでしょうか?
もし関係するのであれば、発行したSQLにおいてのHWMを確認できる方法はありますか?

Anthyhimeさんへ
1件ずつFETCHするよりも一気にコレクションとして取得した方が速いですか?

スキルアップ/キャリアアップ(JOB@IT)