• 締切済み

処理時間について

今、仕事で既存の処理のレスポンス調査をしているのですが、 行き詰ってしまったので質問させていただきます。 本番環境とテスト環境で全く同じ処理を実行した所、テスト環境では 1分程度で処理が正常終了するのに本番環境だと 2時間経過しても処理が終わらず、なぜ同じ処理なのに本番環境と テスト環境で処理時間に違いがありすぎるのか分からず困っています。 処理としては25万件程あるデータ(テキストベース)を PL/SQLで読み込みTable_AにInsert または キーが同じデータが 存在しているならUpdateをし、 それと同時にトリガーで更新前と更新後の値を Log_TableにInsertします。 検証したときの手順としては、 (1)Table_AとLog_TableをCreate (2)トリガーのコンパイル (3)Table_Aのインデックスの作成 (4)PL/SQLのコンパイル (5)Table_AとLog_Tableの統計情報の取得 となっております。 ちなみに、テスト環境と本番環境の両方について、 実行されたSQLの実行計画を取得し比較したのですが、 同じ実行計画になっていました。 また、統計情報を取らずに処理を実行した場合は、テスト環境でも 2時間経過しても処理が終わりませんでした。

  • Oracle
  • 回答数4
  • ありがとう数2

みんなの回答

  • javawater
  • ベストアンサー率11% (6/52)
回答No.4

開発/本番で実行時間が違うというのであれば、下記要因が考えられます。 ハード→ソフトの順に挙げていきます。 ・本番ハードは他の処理を並列で走らせていたりしていませんか?   開発/本番の両方とも、トレース実施時に他のバッチが動いていないのであれば問題は無いと思いますが・・・。 ・本番環境の実行頻度と、開発環境の実行頻度はどれくらいの開きがありますか? Insertを実行すればする程、Insertがしにくくなるように思います(理論的な根拠はありませんが・・・)。 ・ウォーターマークは十分に取られていますか? 

回答No.3

「実行されたSQLの実行計画を取得し比較したのですが」 ということですが、本当にPL/SQLが実行したときに取得した トレースから抽出した実行計画を確認しましたでしょうか。 PL/SQLの中で発行されているSQLと同じSQLをSQL*Plusなどから 発行してもPL/SQLの中で処理されるSQLの実行計画とはことなって 来る可能性もあります。 理由はバインド変数、リテラル値というものなのですが、 PL/SQLの中ではバインド変数が、SQL*Plusではリテラル値が 使われている可能性が高いです。 ですのでNo2の方がおっしゃっているように本番環境と開発環境 それぞれでSQLトレースを取ることをお勧めします。 あと、めんどくさいのであれば本番環境で2時間以上かかる処理を我慢して一度全データを入れ終わってから本番環境にて統計情報を 収集してください。 そうすれば次に統計情報が取られるまでは速くなるはずです。 (ただし、10gであれば毎日夜10時くらいから自動で統計情報が  収集されるので気をつけて下さい。開発環境が早くなる理由は  おそらくこれです。  開発環境と本番環境でそれぞれ  select table_name ,num_rows from user_tables where table_name = 'TABLE_A'としてみてください。  num_rowsの値が異なったりしていませんか?)

  • uresiiwa
  • ベストアンサー率45% (49/107)
回答No.2

まずはSQLをトレースをかけた状態で処理を実行し、トレース内容を確認しましょう。 トレースはチューニングの基本なので、これを取らないと話にならないというぐらいのものですので必ず確認しましょう。 次に、NO.1の方のおっしゃるようにボトルネックを特定していきます。 トレースのtkprof時に経過時間でソートをかけると良いでしょう。 特定のSQLの実行時間のせいなのか、ネットワークなのか、あとはボトルネック原因の追究ですが、分からなければまた質問してください。 SQLトレース方法はOracleパフォーマンスチューニングガイド等で確認してください。

  • lond_nag
  • ベストアンサー率57% (4/7)
回答No.1

SQLの調査よりボトルネック・状況の特定が先かと思います。 ・OSレベルでIO状況、メモリ状況は如何でしょうか? ・ネットワーク負荷はどうでしょうか? ・テーブルのLOCK状況(v$LOCKED_OBJECT)はどうなっているでしょうか? ・2時間経過しても終わらない処理は、延々処理中ということでしょうか?(処理自体が遅い?) ・アーカイブLOGや、表領域の自動拡張でDisk領域が圧迫されたりしていないでしょうか?NextExtentが連続した領域として取れなかったり、DiskFull等でアーカイブが吐けないときにDB自体がストールしたように見える場合があります。 また、テキストベースデータは外部表として読んでいるのでしょうか? UTL_FILEパッケージ? 私の経験上では、DB-Link経由や外部表経由のデータソースが絡む場合はロックや待ち状態になっているケースが多いのですが、テスト環境と本番環境でこういった環境上の違いは無いでしょうか? DBのSGA領域やPGA領域といった条件も同じでしょうか? ANALYZEデータ有無のお話をされていますが、25万件程度のデータ処理で、ルールベースかコストベースかでそれ程の違いが出るケースは、あまり無いと思います。サーバにメモリが無いとか、余程複雑なSQLとかでも無い限りは・・・10g以降はルールベースは無いはずですし。 まずは「SQLの実行が遅い」「ここのロジックで止まっている」等の情報を特定させるのが良いと思います。

関連するQ&A

  • ORACLEのトリガーについて勉強しているのですが現在詰っています。

    ORACLEのトリガーについて勉強しているのですが現在詰っています。 トリガーの内容ですが、table1のレコードがUPDATEかINSERTかDELETEが 実行された時にtable2にそのレコードすべてをINSERTしたいのですが CREATE OR REPLACE TRIGGER test_trg After INSERT or UPDATE or DELETE on table1 for each row  BEGIN   if inserting then    insert into (?);   elsif updating then    insert into (?);   else    insert into (?);   end if;  END; tableを使ってログを残せるようにするためこのトリガーを作ろうとしています。 この様な感じになると思っているのですが、(?)の部分をどう書けばいいのか がよくわかりません。どうしても解らないので教えていただければ幸いです。 何卒よろしくお願いします。

  • PL/SQLのエラー処理について

    PL/SQLを勉強し始めたのですが、テーブルを作成してから、データを流し込むという処理をしたいのですが、テーブルの作成に失敗しらたら、処理を終了させるという処理はできないのでしょうか? それとも、考え方が違うのでしょうか?アドバイスお願いします。 次のようにPL/SQLを作成しています。 例) declare curHandle1 INTEGER; begin curHandle1 := DBMS_SQL.OPEN_CURSOR; DBMS_SQL.PARSE(curHandle1, 'create table xxx as select * from xxx where ID=-1', DBMS_SQL.V7); DBMS_SQL.CLOSE_CURSOR(curHandle1); exception when OTHERS then エラーになったら、処理終了したい(次のブロックにいきたくない) end; declare begin      insert into xxx NOLOGGING values (1,'test'); end; よろしくお願いします。

  • トリガーとシーケンスについて

    DBはOracle9i(Ver9.2.0.1かな?)です。 テスト環境から本番環境にデータ移行する際に テーブルも変更を加えました。 すると変更を加えたテーブルに関連するトリガーが未コンパイル状態になってしまいました。 仕方なく、再コンパイルするとトリガーに記述のあるシーケンスの最終番号が若干ずれていました。 コンパイルすることによってずれることがあるのでしょうか? シーケンスは初期化されたわけではなく、若干ずれてるだけです。 そのシーケンスを使用して登録処理を行っているので一意制約違反がでまくりです。 どなたかアドバイスお願いします。

  • T-SQLでDECODEの様な処理

    質問させて頂きます。 T-SQLでPL/SQLのDECODE()の様な処理を行いたいのですが、T-SQLでは同じ様な処理ができる関数はあるのでしょうか? やりたい処理としては、下記のINSERT文でAテーブル.項目Bに設定する値をCテーブル.項目Bの値が"1"ならBテーブル.項目Bを設定し、 それ以外ならCテーブルの.項目Bを設定するという内容です。 ※INSERT文はT-SQLで行いたい処理をPL/SQLで組んだものです。 INSERT Aテーブル ( 項目A, 項目B ) SELECT Bテーブル.項目A, DECODE(Cテーブル.項目B,'1',Bテーブル.項目B,Cテーブル.項目B) FROM Bテーブル, Cテーブル WHERE 割愛 使用しているバージョンはsqlserver2000を使用しています。 DECODE自体は使用できないことは確認済みです。実現可能か不可能や実現可能な場合はサンプルなどで教えて頂きたいです。 皆様のご助力をお願い致します。

  • shからPL/SQLブロックを実行する方法

    Solaris上でshスクリプト中からPL/SQLを記述したファイルを呼び出して、Oracleのテーブルに対して操作したいのですが、 test.shファイル #/bin/sh sqlplus userid/password@ddzk test.sqlファイル DECLARE … BEGIN INSERT INTO table VALUES( …  ) END; / コマンドラインから $./test.sh を実行すると、 ./test.sh: sqlplus: 見つかりません。 と表示されます。 どなたかshスクリプトからPL/SQLで記述したファイルを実行する 方法をご存知の方、ご教示願います。

  • 無名ブロック内でのDDL実行について

    環境は Linux + oracle 10g R2です。 簡単な無名プロシージャを書いていてはまって しまいました。 分かる方でしたら、あっというまに指摘していただけそうなので こちらに質問しました。 無名ブロック内で以下の事を行いたいのですが、うまく動作を確認できません。 ※以下は意味の無い処理となっていますが、今回説明用に短くしてみました。 ◇実現したい事 1.CREATE TABLE文の実行 (ここではEX01テーブルを作成します) 2.CREATE したテーブルにたいしてINSERT 3.CREATE したテーブルのDROP ◇私の実行結果 $ sqlplus scott/tiger@orcl SQL> SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME ='EX01'; レコードが選択されませんでした。 -- 私の思いでは以下のプロシージャは正常に動作するのでは? -- と思うのですが、以下の通りエラーとなってしまいます。 -- SQL> BEGIN 2 DBMS_UTILITY.EXEC_DDL_STATEMENT('CREATE TABLE EX01 ( C1 NUMBER,C2 VARCHAR2(10))'); 3 INSERT INTO EX01(C1,C2) VALUES(1,'AAA'); 4 DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TABLE EX01'); 5 END; 6 / INSERT INTO EX01(C1,C2) VALUES(1,'AAA'); * 行3でエラーが発生しました。: ORA-06550: 行3、列13: PL/SQL: ORA-00942: 表またはビューが存在しません。 ORA-06550: 行3、列1: PL/SQL: SQL Statement ignored -- -- なので、処理を分割して行ってみました。 -- まずはCREATE TABLEのみ -- SQL> BEGIN 2 DBMS_UTILITY.EXEC_DDL_STATEMENT('CREATE TABLE EX01 ( C1 NUMBER,C2 VARCHAR2(10))'); 3 END; 4 / PL/SQLプロシージャが正常に完了しました。 -- -- CREATE TABLEは正常に動作したようです。 -- SQL> INSERT INTO EX01(C1,C2) VALUES(1,'AAA'); 1行が作成されました。 -- -- INSERT文も正常に動作したようです。 -- SQL> BEGIN 2 DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TABLE EX01'); 3 END; 4 / PL/SQLプロシージャが正常に完了しました。 -- -- なんとDROP TABLEも正常に動作したようです。 -- SQL> SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME ='EX01'; レコードが選択されませんでした。 SQL> そうなんです。3行まとめて記載するとエラーとなるのですが、 上記の通りそれぞれ分けて実行すると正常に動作するのです。 これはどこが悪いのでしょうか? 情けない事に、今日の午後はこれでほとんどつぶれてしまいました。 どなたか助けてください。 以上よろしくお願いします。

  • SQL Server(MSDE2000) : ALTER TABLE

    SQL Server(MSDE2000) : ALTER TABLE した項目に対し、直後に UPDATE で値をセットできない 既存のテーブルを仕様変更するため、列を追加し、初期値で埋める SQL 文を書こうとしていますが、うまく動かず、エラーとなってしまい、原因が判らず困っています。 サンプル SQL 文: ------ CREATE TABLE TEST_TABLE ( TEST_FIELD1 SMALLINT, TEST_FIELD2 SMALLINT) INSERT INTO TEST_TABLE VALUES( 1, 2 ) ALTER TABLE TEST_TABLE ADD TEST_FIELD3 SMALLINT UPDATE TEST_TABLE SET TEST_FIELD3 = 3 ------ ※テスト毎に、必ず DROP TABLE TEST_TABLE されている事が前提です。 上記 SQL 文のうち、1行目~3行目までを抜粋して実行すると、ちゃんと CREATE TABLE され、INSERT され、ALTER TABLE される事を確認しました。 ところが、4行目までを一気に実行しようとすると、 ------ SQL実行中に以下のエラーが発生しました。 エラーコード:207 [Microsoft][ODBC SQL Server Driver][SQL Server]列名 'TEST_FIELD3' は無効です。 SQLステータス:S0022 ------ となってしまい、UPDATE で初期値を埋める事ができません。 しかも、UPDATE に失敗するどころか、2行目の INSERT から以降が結果に反映されなくなるという状況に陥ってしまいます。 また、既存のテーブルの仕様変更が目的なので、その状況に近づけるために、まず、 ------ CREATE TABLE TEST_TABLE ( TEST_FIELD1 SMALLINT, TEST_FIELD2 SMALLINT) INSERT INTO TEST_TABLE VALUES( 1, 2 ) ------ を実行し、既存のテーブル(とレコード内容)が存在する状態を作り出された事を、ツール等で確認してから、 ------ ALTER TABLE TEST_TABLE ADD TEST_FIELD3 SMALLINT UPDATE TEST_TABLE SET TEST_FIELD3 = 3 ------ の2行を実行してみると、やはり UPDATE は失敗し、前述と同じエラーが発生します。 またこの場合、ALTER TABLE の実行結果も反映されていません。(つまり、TEST_FIELD3 が列追加されていない) もちろん、ALTER TABLE だけを実行した場合には、ちゃんと列は追加されます。 その後に、UPDATE を実行すれば、ちゃんと追加列に初期値がセットされます。 どうやら、「一回の SQL 文の実行の中で、ALTER TABLE によって新設した列に対しては、UPDATE などでのアクセスはすぐにはできない」のではないか?という状況のようなのです。一回の SQL 文の実行の中において、何らかのトランザクション動作っぽい挙動を感じます。 つまり、ALTER TABLE で追加された列は、その時点ではまだ完全にシステムに認知されていないため、直後の UPDATE 文で認識できずに失敗するのではないか?と。そして、そこでのエラー発生が、ロールバック的に実行した処理をキャンセルしてしまうため、結果として、ALTER TABLE が実行されなかった事になったり、INSERT が実行されなかった事になったりしているのではないか?と思う次第です。 考えられる回避策としては、SQL 文を別々に作成し、個別に実行すれば良いだけの事なのですが、できれば、SQL 文一つにまとめたいと考えています。 どなたか、こういった現象に対する原因・理由の説明、或いは回避策など、何か情報をお持ちの方はいらっしゃいませんでしょうか? 宜しくお願いします。

  • insert1つの処理でもトランザクションは必要?

    お世話になります。 現在、MYSQLデータベースを使用したプログラムを書いており、 そこでトランザクションについて質問があります。 トランザクションとは、複数の処理がすべて成功した場合に正式な処理を実行(commit)、1つでも失敗した場合は元に戻す(rollback)というようなことかと思うのですが、 では、1つの処理のみの場合は、トランザクションを使用する必要はないのでしょうか? 例えば、 ・あるテーブルにデータをinsertしたい。 このような単一の処理を書く場合でも、 以下のようにトランザクションを使うべきでしょうか? $dsn = 'mysql:dbname=〇〇〇;host=〇〇〇;charset=utf8'; $user = 'user'; $pwd = 'pwd'; //DB接続 try { $pdo = new PDO($dsn, $user, $pwd); } catch (PDOException $e) { die('DB接続失敗'); } //トランザクション開始 $pdo->beginTransaction(); //INSERT try { $sql = 'INSERT into table (test1, test2, test3) VALUES (:a, :b, :c)'; $st= $pdo->prepare($sql); $ret = $st->execute(array( ':a' => $a, ':b' => $b, ':c' => $c, )); if (!$ret) { throw new Exception('INSERT 失敗'); } //commit $pdo->commit(); } catch (PDOException $e) { //rollback $pdo->rollBack(); } $pdo = null; ※前提として、テーブルを使用するユーザーは多数います。 ご存知の方、ご回答いただけるれば幸いです。 よろしくお願い致します。

    • ベストアンサー
    • PHP
  • トリガーの設定方法

    いま、まったく同じ型のTABLE1,TABLE2の2つのテーブルがあり、 TABLE1にInsertやUpdateがかかると、自動的にTABLE2の方にも 同じようなInsertやUpdateが走る仕組みを作りたいと考えています。 TABLE1にトリガーを設定すれば可能ということは判ったのですが、 どのようにトリガーを記述すればわからず、困っています。 特に、「AS」以降の記述方法が判りません。 TABLE1にかかったクエリを同じようにTABLE2にもかかるように するにはどのように記述すればいいのでしょうか。

  • エージェントのジョブの遅さ

    すいません、まだはじめたばかりで全然良くわからないのですが、 維持管理でこのSQL文で処理速度の遅さにひっかかっています。 自分で作ったものではないのでいまいちよくわかってないのですが、 エージェントのジョブで1日3回行っている処理、同じ件数(インデックスがまったく一緒)になるよう、INSERTをかける処理なのですが、 INSERT INTO TABLE_A SELECT AAA, BBB, CCC, 0, 0 FROM TABLE_B WHERE A + B + C NOT IN (SELECT A + B + C FROM TABLE_A) というようなTRANSACT SQLになっています。 TABLE_AにないものをTABLE_Bから持ってくるということだと思います。 件数は約13万件、なぜか1時間かかるようで、他の処理のレスポンスに影響が出てきています。 根本的にこういうやり方はまずいのでしょうか?処理を遅くする要因があるのでしょうか? もしあるようなら改善策を教えていただけると助かります。 環境はSQL SERVER 2005です。 どちらもA,B,Cにインデックスがあります ちょっと事情があって、大きくやり方を変えられないので、エージェントのジョブ内でもっと早くできる方法が知りたいです。 なにとぞ、よろしくお願いいたします。