在处理行之前对行进行计数以证明反馈的最佳实践

时间:2018-09-28 14:42:18

标签: sql oracle performance plsql oracle11g

我正在寻找在实际使用微积分之前要计算其行数的最佳方法。原因是我需要证明“已分析的​​1/100行”,“已分析的​​2/100行”等反馈。

我说的是大约7000行,执行计数的时间相差2分钟。

最糟糕的是,现在我必须使用查询来获取计数,然后打开一个与上一个完全相同的游标(计数除外)并开始分析,因此代码是复制,并且每次我需要修改where子句时,我都必须做两次。

我想到将光标放在一个局部变量中,然后在pl / sql while循环中运行以增加一个计数器,但是我不确定性能,所以这就是为什么我要向您提出建议的原因。

真的希望答案不会是使用包含总行数的已打开游标的某些魔术属性,因为我会觉得很愚蠢:(

除非获得可靠的性能提升,否则我宁愿不使用count(*)而不是(partition by),因为我认为一眼难以理解。

感谢所有人

2 个答案:

答案 0 :(得分:0)

您可以使用COUNT(*) OVER()

DECLARE
  CURSOR my_cur IS
  SELECT t.c, COUNT(*) OVER() AS total FROM tab t;

  v_c INT;
  v_total_rows INT;
  v_i INT :=0;
BEGIN
  OPEN my_cur;

  LOOP
    EXIT WHEN my_cur%NOTFOUND;
    FETCH my_cur INTO v_c, v_total_rows;

    IF v_i = 0 THEN
      DBMS_OUTPUT.put_line('Total number of rows to process: ' || v_total_rows);
    END IF;

    DBMS_OUTPUT.PUT_LINE('Current value :' || v_c);

    DBMS_OUTPUT.PUT_LINE('Progress: ' || 100.0 * v_i / v_total_rows || '%');
    v_i := v_i + 1;
  END LOOP;
  CLOSE my_cur;
END;
//

db<>fiddle demo


您可以使用SET_SESSION_LONGOPS来代替打印到DBMS_OUTPUT

答案 1 :(得分:0)

如果您需要了解表的全部行数,则可以使用数据字典的num_rows(只要统计信息是最新的):

CREATE TABLE mytest AS SELECT * FROM all_objects;

BEGIN dbms_stats.gather_table_stats(user, 'MYTEST'); END;
/

SELECT num_rows FROM user_tables WHERE table_name='MYTEST';
-- 60715

如果您的查询更复杂并且可以过滤出行或执行其他一些奇特的事情,并且如果对预期的行数的估计足够好,则可以使用Oracle的内置查询计划程序。它需要弄清楚需要多少行才能找到查询它的最佳方法:

EXPLAIN PLAN SET STATEMENT_ID = 'st1-seq' FOR 
  SELECT * FROM mytest WHERE object_type = 'SEQUENCE';
SELECT cardinality from plan_table WHERE statement_id='st1-seq' and operation='SELECT STATEMENT';
10

EXPLAIN PLAN SET STATEMENT_ID = 'st1-java' FOR 
  SELECT * FROM mytest WHERE object_type = 'JAVA CLASS';
SELECT cardinality from plan_table WHERE statement_id='st1-java' and operation='SELECT STATEMENT';
37563