2011-09-05 10 views
2

これは私を約4時間悩ませているので、何か助けを求める時だと思った。私は類似したオンラインのものは何も見つかりませんが、主に値が非常に特殊で、何を探すべきかわからないからです...クエリーが変更された後でも、Oracleクエリーが同じ場所にスタックされる

これは私がOracleスクリプトで実行している問題ですSQLPlus 10.2.0.5。

問題:

(名前と実際のデータは、容疑者の身元を保護するために変更されました) は、私は少しのようになりMONKEYSと呼ばれるテーブルとMONKEY_PUZZLESというテーブルを、持っています

MONKEYS

  • MONKEY_ID
  • GIRAFFE_ID
  • MONKEY_PUZZLE_ID

MONKEY_PUZZLES

  • MONKEY_PUZZLE_ID
  • GIRAFFE_ID

MONKEY_PUZZLES.GIRAFFE_IDとMONKEYS.GIRAFFE_ID一致が、N MONKEY_PUZZLEあたりサル(SO MONKEY_PUZZLES.GIRAFFE_ID 1が一致する可能性がありますされていますMONKEY.MONKEY_ID 1、2、および334)。

MONKEY_PUZZLES.MONKEY_PUZZLE_IDフィールドに基づいてMONKEYS.MONKEY_PUZZLE_IDフィールドを設定したいのは、現在MONKEYS.MONKEY_PUZZLE_IDフィールドがnullであるためです。

  • MONKEYS.MONKEY_ID(インデックスを持つ主キー)
  • MONKEYS.GIRAFFE_ID
  • MONKEY_PUZZLES.MONKEY_PUZZLE_ID(インデックスを持つ主キー)
  • MONKEY_PUZZLES.GIRAFFE_ID

:私は上のインデックスを持っていますまた、MONKEYSテーブルには160万以上の行があり、MONKEY_PUZZLESテーブルには50,000以上の行があります。

私はもともと次のクエリを使用していた

UPDATE MONKEYS M SET M.MONKEY_PUZZLE_ID = 
    (SELECT MP.MONKEY_PUZZLE_ID FROM MONKEY_PUZZLES MP 
    WHERE M.GIRAFFE_ID = MP.GIRAFFE_ID 
    AND MP.GIRAFFE_ID IS NOT NULL); 

しかし、このスクリプトは完全92.67パーセント0%から取得するのに約2分かかります、それは94%に到達するために25分かけてもかかりましたコンプリート。私は最終的にスクリプトを停止しました。私はそれを数回実行しました(私は異なるインデックスとDBMS_STATSを使って遊んでいました)が、毎回92.67%になってしまいました。

私はそれが私のスクリプトでなければならないと思った。

UPDATE MONKEYS M2 SET M2.MONKEY_PUZZLE_ID = 
    (SELECT X.MPID FROM 
    (SELECT M.MONKEY_ID MID, MP.MONKEY_PUZZLE_ID MPID 
    FROM MONKEYS M INNER JOIN MONKEY_PUZZLES MP 
    ON MP.GIRAFFE_ID = M.GIRAFFE_ID) X 
    WHERE X.MID = M2.MONKEY_ID); 

しかし、それはゴミだった:私は、戻って振り出しに戻ったバナナを食べ、「Oook」多くのことを言ったとはるかに明示され、次の変動スクリプトを、思い付きました。私のインデックスでも、2%になるのに5分以上かかりましたので、私はそれを解凍しました。

私はその後、私はとかなり満足していた以下の変動、思い付いた:しかし

UPDATE MONKEYS M SET M.MONKEY_PUZZLE_ID = 
    (SELECT MP.MONKEY_PUZZLE_ID 
    FROM MONKEY_PUZZLES MP 
    WHERE M.GIRAFFE_ID = MP.GIRAFFE_ID 
    AND EXISTS 
    (SELECT 1 FROM MONKEY_PUZZLES MP2 
     WHERE M.GIRAFFE_ID = MP2.GIRAFFE_ID)); 

、と私は本当に私の目を信じることができなかった、このスクリプトは、ほぼ正確に最初のように振る舞っ。約2分で実行され、0%から92.67%まで完了し、次に何かを得るために絶対的な年齢を取る。 92.67%とは何ですか?

ブロックの総数は41,717であり、大幅に減速する前に約38,000ブロックに達します。あなたが迷っている場合は

、私は%の年齢の完全なを計算するために、別のSQLPLUSセッションで次の問合せを使用しています:

(これのバリエーションです: http://searchoracle.techtarget.com/tip/Tracking-the-progress-of-long-running-queries
SELECT X.*, TO_CHAR(SYSDATE, 'HH24:MI:SS') TIMESTAMP 
    FROM (select sid, serial#, opname, sofar, totalwork, 
    round(sofar/totalwork*100,2) "% Complete" from v$session_longops) X 
    WHERE "% Complete" < 100 and totalwork > 0; 

貧しい虎を苦しみから救うのを助けてください!

P.S.私はスクリプトを一晩中実行したままにしておき、100%に達すると午前中に更新します。

EDIT:最終的にわずか57分後に100%に達しました(それほど悪くない)が、2分で92.67%に達したと考えると、かなりひどいです!

+0

テーブルのオプティマイザ統計を作成し、対応するステートメントの実行計画を取得します。さらに、クエリが停止しているときに待機イベントが何であるかを確認する必要があります。 – steve

+0

実行計画は本当にここで助けになるでしょう。また、すべてのmonkeys.monkey_puzzle_idフィールドがNULLか、 'WHERE monkey_puzzle_id IS NULL'を追加すると助けになるでしょうか? – eaolson

+0

ありがとう@eaolson。私のmonkeys.monkey_puzzle_idsはすべてnullです。 @steve、私は 'DBMS_STATS.GENERATE_SCHEMA_STATS(OWNNAME => 'JUNGLE'、OPTIONS => 'GATHER AUTO')'を使って、私が設定したインデックスの統計を生成しました。助けることができる他に何かありますか? – LordScree

答えて

4

私はあなたが見ている特定の症状のために何の説明もない - おそらく、更新のための実行計画がそれを説明するのに役立つだろうが - しかし、いずれにしても、私は、これはパフォーマンスが向上することを期待します:

MERGE INTO monkeys m 
USING monkey_puzzles mp 
ON (mp.giraffe_id = m.giraffe_id) 
WHEN MATCHED THEN UPDATE SET m.monkey_puzzle_id = mp.monkey_puzzle_id 
+0

こんにちは@DaveCosta、ありがとう私は間違いなくこれを与える。私は前にマージを使用していないことを認めて恥ずかしいです。興味のないところから、SQLPlusで実行計画を取得する方法は何ですか?私はGUIにアクセスできない。特定の問題の説明を聞くことに非常に関心がありますので、今後は避けてください。ありがとう – LordScree

+0

これは優秀だった。 17.31秒!!私は進歩を確認する時間さえなかった、それは速すぎました!私は間違いなく将来的に 'MERGE'を検討するつもりです。再度、感謝します。 – LordScree

+2

@LordScree - 実行計画を表示する1つの方法は、EXPLAIN PLAN(http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/ex_plan.htm)です。可能な場合は、DBMS_XPLAN.DISPLAY_CURSOR(http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_xplan.htm#CACFJGHG)を使用する方が適しています。 –

1

このような問題が発生した場合、最も簡単なことは完全に無視することです。注:問題の理由を解決しません!このクエリとあなたのものについては、実際にはmonkey_puzzlesのgiraffe_idのインデックスが必要です。 Giraffe_id、monkey_puzzle_idはさらに良いでしょう。

declare 

    i number(10) := 0; 

begin 

    for xx in (select rowid as rid, giraffe_id 
       from monkeys) loop 

    UPDATE MONKEYS M 
     SET M.MONKEY_PUZZLE_ID = (SELECT MP.MONKEY_PUZZLE_ID 
            FROM MONKEY_PUZZLES MP 
            WHERE MP.GIRAFFE_ID = xx.giraffe_id) 
     WHERE rowid = xx.rid 
      ; 

    i := i + 1; 
    if mod(i,1000) = 0 then 
     commit; 
     -- and some show-boating from memory (if you're using PL\SQL) 
     dbms_application_info.set_module('Updating Monkeys', 'Total: ' || i); 
    end if; 

    end loop; 
    commit; 

end; 
/
+0

お返事ありがとうございます。私はあまりにも多くの機会にあなたのマントラを使用したことを認めなければなりません!私はあなたのループスクリプトを試してみましたが、かなり遅くなりました(5分後に<2%)。毎回特定の数の行だけを実行しているので、それは92.67%を超えていたことは間違いありません。このアプローチのもう一つの欠点は、それが進むにつれてコミットしていることです。間違ってしまうとロールバックすることはできません。しかしもう一度ありがとう。 – LordScree

+0

私はそれが私のマントラ@LordScreeではないことを願っています! – Ben

関連する問題