1

大きなテーブルがあり、レコード ( > 1,000,000 ) を反復処理し、各テーブル >= 1 の別の 2 セットに基づいていくつかのチェックを実行し、結果をテキスト ファイルに出力したいと考えています。

これを行うPL\SQLには数時間かかりますが、それを最適化するか、または(テーブルへの)選択のみで書き込みがないため、並列化可能なclojureプログラムとしてこれを書き直すことができます。

質問: 1 PL/SQL の最適化には、どのような課題/制限がありますか?

2 PL/SQL の最適化と比較して、コードを clojure に移行することには大きな利点がありますか?

編集 これがその肉です

  OPEN cur;

  LOOP
     FETCH cur INTO l_cur;

     EXIT WHEN cur%NOTFOUND;

     SELECT NVL (dUM ( (total - total_old)), 0),
            NVL (dUM ( (new - old)), 0)
       INTO li_debt, li_debt
       FROM tbl1
      WHERE     accounting_date = l_cur.accounting_date
            AND USER_ID = l_cur.USER_ID
            AND USER_ACCOUNT = l_cur.USER_ACCOUNT;

     SELECT NVL (
               dUM (
                  DECODE (a.DEBITS,
                          'foo', ABS (amount),
                          ABS (amount) * -1)),
               0)
               amount
       INTO li_dad_bill
       FROM daily_trandactiond d, ACCOUNTS a
      WHERE     d.USER_ID = l_cur.USER_ID
            AND d.USER_ACCOUNT = l_cur.USER_ACCOUNT
            AND d.f_actual >= l_cur.accounting_date
            AND d.acc_code = a.acc_code
            AND d.concept = a.conc
            AND ( d.tarrif = a.tariff or (d.acc_code, d.concept) NOT IN
                    (SELECT UNIQUE acc_code, conc
                       FROM ACCOUNTS
                      WHERE TRIM (tariff) Id NOT NULL)
                 );

     SELECT NVL (
               dUM (
                  DECODE (a.DEBITS,
                          'foo', ABS (amount),
                          ABS (amount) * -1)),
               0)
               amount
       INTO li_dad_coll
       FROM daily_trandactiond d, ACCOUNTS a
      WHERE     d.USER_ID = l_cur.USER_ID
            AND d.USER_ACCOUNT = l_cur.USER_ACCOUNT
            AND d.f_actual = l_cur.accounting_date
            AND d.acc_code = a.acc_code
            AND d.concept = a.conc
            AND dUBdTR (d.acc_code, 3, 1) <> '1';

     IF ABS ( (li_debt - li_debt) - (li_dad_bill + li_dad_coll)) > 0.9
     THEN
        DBMd_OUTPUT.
         put_line (
              LPAD (TO_CHAR (l_cur.USER_ID) || ',', 20, ' ')
           || LPAD (TO_CHAR (l_cur.USER_ACCOUNT) || ',', 20, ' '));
     END IF;
  END LOOP;

  CLOdE cur;
4

1 に答える 1

5

まあ、それは多くのことに依存します。

主なことは明らかに、SQL ステートメントを最適化する能力とロジックを Clojure に書き直す能力の程度です。私は Clojure には詳しくありませんが、効率的な並列ソリューションを作成するには、少なくとも一般的な SQL と、特に Oracle について十分に理解している必要があると思います。多くの単一行ステートメントを並行して実行することは、パフォーマンスの点で優れた戦略ではありません

2 番目に考えられることは、ボトルネックに依存するということです。たとえば、現在のボトルネックがディスク IO である場合、並列化によってパフォーマンスを向上させることはできません。プログラムがどこで時間を費やしているかを知ることは役に立ちます (1000000 行の大きな SELECT か、後続のチェックか、それともファイルへの書き込みか?)。

原則として、適切に最適化された SQL ステートメントよりも優れたパフォーマンスを実現するために、自作の並列ソリューションを使用することは難しいでしょう。これは、結合や並べ替えなどの多くの操作が、行ごとのロジックよりもセット ロジックの方が効率的であり、SQL を使用するとセットで考える方が簡単だからです。

今、あなたのプログラムはおそらく次のようなものだと思います:

FOR cur IN (SELECT *  /*100000 rows*/ FROM view) LOOP

   check(cur.x, cur.y); -- check row by row, lookup to other tables

   IF (condition) THEN

      write_to_file(cur.z);

   END IF;

END LOOP;

メイン カーソル内の結合を使用してほとんどの条件を簡単に書き直すことができれば、わずかな変更だけでパフォーマンスが大幅に向上する可能性があります。

たとえば、条件がコンテンツに大きく依存しているなどの理由でそれができない場合、個々のステートメントがすでに効率的であると仮定すると、これは並列化の適切なケースになる可能性があります。その場合、作業を多かれ少なかれそれらの間で均等に分散する追加の where 句を使用して N 個のジョブを実行し、結果を連結できます。

于 2013-08-20T16:09:52.040 に答える