2

さまざまなテーブルから約 100.000 行を選択し、それらを別のデータベースの別のテーブルに挿入する Oracle sql ツールからの挿入を実行しましたが、これは 3 分で終了します。オラクルのストアド プロシージャまたは PLSQL 内で同じクエリを実行すると、約 2 時間実行されます。詳細については、ソース Oracle 11g と宛先 Oracle 10g を使用します。

ストアド プロシージャ (ストアごとに約 2 時間かかります):

CREATE OR REPLACE PROCEDURE MGS.TRANSFER_DATA(a_date in varchar2) -- yyyymmdd
BEGIN
 BEGIN
 FOR xx IN(
  SELECT STR_CD FROM MGS.STORE ORDER BY STR_CD ASC
 ) LOOP
  CALL_LOG(xx.STR_CD,a_date,sysdate,"START INSERT");
  INSERT INTO STOCK@BBS
  SELECT
   STR_CD, STK.DT, PROD_CD, QTY, ORDER_QTY, ORDER_QTY
  FROM
   MGS.STOCK STK, MGS.SALE SAL
   WHERE STK.STR_CD = xx.STR
   AND STK.STR_CD = SAL.STR_CD(+)
   AND STK.PROD_CD = SAL.PROD_CD(+)
   AND STK.DT = SAL.DT(+)
   AND STK.DT = a_date;
 CALL_LOG(xx.STR_CD,a_date,sysdate,"INSERT SUCESSFULL");
END LOOP;
END;

END TRANSFER_DATA;

1店舗のクエリを試しました(3分かかります):

INSERT INTO STOCK@BBS
SELECT
 STR_CD, STK.DT, PROD_CD, QTY, ORDER_QTY, ORDER_QTY
FROM
 MGS.STOCK STK, MGS.SALE SAL
 WHERE STK.STR_CD = 'STORE01'
 AND STK.STR_CD = SAL.STR_CD(+)
 AND STK.PROD_CD = SAL.PROD_CD(+)
 AND STK.DT= SAL.DT(+)
 AND STK.DT= '20120801'; -- yyyymmdd
4

3 に答える 3

2

私の推測では、プロシージャ内のクエリに対して生成されるプランは、スタンドアロン クエリに対して生成されるプランとは大きく異なります。スタンドアロン バージョンでは、オプティマイザーが適切な仮定を立てることができる定数が含まれています。定数がないと、オプティマイザーは処理を続行することが少なくなるため、おそらくいくつかの異なる決定を下すことになります。これを試して:

スタンドアロン クエリの実行プランを取得します。

次の実行計画を取得します (ループをサブクエリ リファクタリング句に置き換えるだけです)。

WITH xx AS (SELECT STR_CD, '20120801' AS A_DATE
              FROM MGS.STORE ORDER BY STR_CD ASC)
  SELECT STR_CD, "DATE", PROD_CD, QTY, ORDER_QTY, ORDER_QTY
    FROM MGS.STOCK STK, MGS.SALE SAL
    WHERE STK.STR_CD = xx.STR AND
          STK.STR_CD = SAL.STR_CD(+) AND
          STK.PROD_CD = SAL.PROD_CD(+) AND
          STK."DATE" = SAL."DATE"(+) AND
          STK."DATE" = xx.A_DATE

( という名前の列を二重引用符で囲む必要があることに注意してくださいDATE。これに遭遇しなかったことに驚いています)。プランを比較します。2 番目の計画は、サブクエリの因数分解句が存在するため、明らかに最初の計画とは異なりますが、一致する要素を比較してみてください。特に、最初のクエリがインデックスを使用し、2 番目のクエリが全テーブル スキャンを実行している要素を探します。

必要に応じて 2 番目のクエリにヒントを追加して、最初のクエリと可能な限り一致するプランを取得します。

もう 1 つの可能性はありそうにないと思いますが、ログの呼び出しに時間が費やされている可能性があります。にやにや笑いの場合は、ログアウトをコメントして、それが効果があるかどうかを確認してみてください(私は期待していませんが、これまでの人生は私が期待していなかったものでいっぱいです:-)。

共有してお楽しみください。

于 2012-09-07T12:04:12.840 に答える
1

plsqlのクエリが遅くなる理由はわかりませんが、解決策は次のとおりです。

CREATE OR REPLACE PROCEDURE MGS.TRANSFER_DATA(a_date in varchar2) -- yyyymmdd
BEGIN
 BEGIN
 FOR xx IN(
  SELECT STR_CD FROM MGS.STORE ORDER BY STR_CD ASC
 ) LOOP
  CALL_LOG(xx.STR_CD,a_date,sysdate,"START INSERT");
  execute immediate '
  INSERT INTO STOCK@BBS
  SELECT
   STR_CD, STK.DT, PROD_CD, QTY, ORDER_QTY, ORDER_QTY
  FROM
   MGS.STOCK STK, MGS.SALE SAL
   WHERE STK.STR_CD = ''' || xx.STR || '''
   AND STK.STR_CD = SAL.STR_CD(+)
   AND STK.PROD_CD = SAL.PROD_CD(+)
   AND STK.DT = SAL.DT(+)
   AND STK.DT = ''' || a_date || '''
 ';
 CALL_LOG(xx.STR_CD,a_date,sysdate,"INSERT SUCESSFULL");
END LOOP;
END;
于 2012-09-14T08:53:04.613 に答える
0

これらすべての挿入を、ストアごとに dbms_job によって並行して開始してみてください。従来の sql と同じパフォーマンスを実現できる可能性があります。dbms_parallel_execute も役立つと思います。http://www.oracle-base.com/articles/11g/dbms_parallel_execute_11gR2.php を参照してください。

于 2012-09-07T12:05:03.293 に答える