1

我有一个大表,希望遍历记录(> 1,000,000),基于另外 2 个集合执行一些检查,每个表 >= 1 并将结果输出到文本文件。

执行此操作的 PL\SQL 需要几个小时,我可以对其进行优化,或者我可以将其重写为可并行化的 clojure 程序,因为只有选择而没有写入(对表)。

问题: 1 在优化 PL/SQL 方面存在哪些挑战/限制?

2 将代码迁移到 clojure 以优化 PL/SQL 是否有主要的好处?

编辑 这是它的肉

  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 才能产生一个高效的并行解决方案。并行运行许多单行语句在性能方面并不是一个好的策略

想到的第二件事是它将取决于瓶颈。例如,如果现在的瓶颈是磁盘 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 回答