3

特定の日付範囲の間の月の日付オブジェクトのコレクションを返すクエリを実行しています。クエリは問題なく動作しますが、非常に遅いです (私のローカル マシンでは約 2 秒、企業の開発環境では約 30 秒)。ここにあります:

SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum) AS MONTH
FROM all_objects
WHERE ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum) <= TO_DATE('200805', 'YYYYMM')

現在、1 か月しか返されませんが、2 番目の日付文字列を拡張すると、さらに多くの値が返されます。

2 つの質問があります。まず、なぜこれはとても遅いのですか?Oracle 関数がクエリを実際に遅くすることは知っていますが、私の職場の開発マシンでは約 30 秒かかります。

2 つ目の、より不可解な質問: 範囲を「201805」に拡張すると、実行時間が数分の 1 秒に短縮されるのはなぜですか? 範囲が広いほど時間がかかると思います。逆効果のようです。

4

4 に答える 4

4

代わりにこれを使用して、

SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) AS MONTH
FROM (select level rn from dual connect by level < 4000)
WHERE ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) <= TO_DATE('200805', 'YYYYMM')
;

これにより、2 つの環境間で異なる可能性が高い all_objects が回避されます。

all_objects は複雑なビューであるため、上記で使用したインライン ビューほどパフォーマンスは高くありません。"connect by" 構文を使用したくない場合は、整数のテーブルを作成して使用します。

于 2010-07-19T14:42:48.283 に答える
3

MONTHS_BETWEEN()関数を使用して任意の4000か月の制限を取り除く、Janekの関数のわずかな変形

SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) AS MONTH 
  FROM ( select level rn 
           from dual 
           connect by level < abs(months_between(TO_DATE('200804', 'YYYYMM'),TO_DATE('201805', 'YYYYMM')))+2
       ) 
 WHERE ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rn) <= TO_DATE('201805', 'YYYYMM') 
; 
于 2010-07-19T14:55:40.917 に答える
2

インライン ビューを使用する必要はなく、使用されている日付関数が多すぎます。それをすべてスキップすると、次のようになります。

SQL> var START_YM varchar2(6)
SQL> var END_YM varchar2(6)
SQL> exec :START_YM := '200804'; :END_YM := '201805'

PL/SQL procedure successfully completed.

SQL>  select add_months(to_date(:START_YM,'yyyymm'),level-1) m
  2     from dual
  3  connect by level <= months_between(to_date(:END_YM,'yyyymm'),to_date(:START_YM,'yyyymm'))+1
  4  /

M
-------------------
01-04-2008 00:00:00
01-05-2008 00:00:00
01-06-2008 00:00:00
<... 116 rows skipped ...>
01-03-2018 00:00:00
01-04-2018 00:00:00
01-05-2018 00:00:00

122 rows selected.

これはさらに簡単に見えます...

よろしく、ロブ。

于 2010-07-20T09:28:28.103 に答える
0

ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum)ここでの難しさの一部は、ALL_OBJECTSビューのすべての行を評価する必要があることです。where句を書き直すと、COUNTの代わりにCOUNTSTOPKEYを使用した別のプランが使用されます。

代わりに、以下のクエリを試してください。これは私のものではかなり速く実行されました。

SELECT ADD_MONTHS(TO_DATE('200804', 'YYYYMM'), -1+rownum) AS MONTH
FROM all_objects
where 
  months_between(date '2008-05-01, date '2008-04-01') >= rownum

201805を使用してクエリをより高速に実行することについて行ったコメントは、実際には間違っています。クエリは高速に実行されません。最初の行が高速に戻るだけなので、高速に見えます。

終了日を2008-05-01に設定すると、行を返す前にALL_OBJECTSテーブル全体を実行する必要がありますが、期間が長くなると、バッファーがいっぱいになると行が返されます。各クエリは、同じ時間内に完了するまで実行されます。

于 2010-07-21T11:37:55.083 に答える