2012-02-18 34 views
0
create or replace procedure prcdr_Clustering is 
v_sampleCount number; 
v_sampleFlag number; 
v_matchPercent number; 
v_SpendAmount Number(18, 2); 
cursor cur_PDCSample is 
SELECT * 
    FROM TBL_BIL 
WHERE UDF_CHK = 'N';  
rec_Pdcsample TBL_BIL%rowtype; 
BEGIN 
OPEN cur_PDCSample; 
LOOP 
FETCH cur_PDCSample 
    into rec_Pdcsample; 
EXIT WHEN cur_PDCSample%NOTFOUND; 
SELECT COUNT(*) 
    INTO v_sampleCount 
    FROM TBL_BIL 
WHERE UDF_TOKENIZED = rec_Pdcsample.UDF_TOKENIZED; 
IF v_sampleCount <> 0 THEN 
    UPDATE TBL_BIL 
    SET UDF_CHK = 'Y' 
    WHERE UDF_TOKENIZED = rec_Pdcsample.UDF_TOKENIZED; 
    IF v_sampleCount > 1 THEN 
    v_sampleFlag := 1; 
    ELSE 
    IF v_sampleCount = 1 THEN 
     v_sampleFlag := 2; 
    ELSE 
     v_sampleFlag := 0; 
    END IF; 
    END IF; 
    UPDATE TBL_BIL 
    SET UDF_SAMPLECOUNT = v_sampleCount, UDF_SAMPLEFLAG = v_sampleFlag 
    WHERE uniqueid = rec_Pdcsample.uniqueid; 
    UPDATE TBL_BIL 
    SET UDF_PID = rec_Pdcsample.uniqueid 
    WHERE UDF_TOKENIZED = rec_Pdcsample.UDF_TOKENIZED; 
    UPDATE TBL_BIL 
    SET UDF_PIDSPEND = v_SpendAmount 
    WHERE uniqueid = rec_Pdcsample.uniqueid; 
    UPDATE TBL_BIL 
    SET UDF_MATCHPERCENT = 1 
    WHERE uniqueid <> rec_Pdcsample.uniqueid 
    AND UDF_TOKENIZED = rec_Pdcsample.UDF_TOKENIZED; 
END IF; 
IF cur_PDCSample%ISOPEN THEN 
    CLOSE cur_PDCSample; 
END IF; 
OPEN cur_PDCSample; 
END LOOP; 
IF cur_PDCSample%ISOPEN THEN 
CLOSE cur_PDCSample; 
END IF; 
end PrcdrClustering; 

需要几天的时间来执行,我的表有225,846行数据。请有人可以帮我优化这个过程,Oracle 10g

我的表的结构是: -

UNIQUEID NUMBER Notnull primary key 
VENDORNAME VARCHAR2(200)    
SHORTTEXT VARCHAR2(500)    
SPENDAMT NUMBER(18,2)     
UDF_TOKENIZED VARCHAR2(999)    
UDF_PID NUMBER(10)    
UDF_SAMPLEFLAG NUMBER(4)    
UDF_SAMPLECOUNT NUMBER(4)    
UDF_MATCHPERCENT NUMBER(4)    
UDF_TOKENCNT NUMBER(4)    
UDF_PIDSPEND NUMBER(18,2)     
UDF_CHK VARCHAR2(1) 
+1

你的代码有两个表。另一张桌子的结构是什么?你还有什么样的索引?你有没有检查过它们?此外,你可以使用oracles'explain plan'来检查你的查询的执行计划,甚至你的整个过程(我不知道)... – ZeissS 2012-02-18 10:11:03

回答

0

我不知道为什么,但你打开cur_PDCSample,其中选择(我怀疑)数以千计的记录。然后,在循环中,关闭游标并重新打开它,每次只处理返回的第一条记录。

如果您打开光标一次,处理每个记录然后关闭它,您的过程可能会快得多。

实际上,由于您并不总是将TBL_BIL.UDF_CHK更新为'Y',所以在我看来您的当前过程可能无限运行。

4

从哪里开始?我有一些要点。

  1. 您正在进行批量更新;这意味着bulk collect ... forall会更有效率。
  2. 您正在对同一张表进行多次更新,这会使DML的数量增加一倍。
  3. 正如你已经从表中选择的那样,重新输入它来做另一个计数是毫无意义的,使用分析函数来得到你需要的结果。
  4. 缩进,缩进,缩进。使您的代码更易于阅读。
  5. 您可以使用elsif减少报表的数量进行评估(非常非常小的胜利)
  6. 如果uniqueid是唯一可以使用rowid更新表。
  7. 您正在更新udf_pidspend为空,无论这是否为有意或无需为此进行单独更新。
  8. 您可以在光标中做更多的事情,但显然不需要选择所有内容,这将减少您需要从磁盘读取的数据量。
  9. 您可能需要一些提交;尽管这意味着如果中途失败,你不能回滚。
  10. 我希望tbl_bil被索引上uniqueid
  11. 作为GolzeTrol注意到你多次打开游标。这是没有必要的。

作为一般规则:

  • 如果你想,如果不选择/更新或删除表中做一次,如果可能的,并且几次越好。
  • 如果您正在进行批量操作,请使用bulk collect
  • Neverselect *
  • 使用rowid如果可能的话就避免了所有指标的问题。

这只会在11G工作,我最近回答this question,我提供我自己的这个实施限制之前,11G买卖版本的方式连接到Ollie's,汤姆凯特的和Sathya's

我我不完全确定你要在这里做什么,所以请原谅我,如果逻辑有点关闭。

create or replace procedure prcdr_Clustering is 

    cursor c_pdcsample is 
    select rowid as rid 
     , count(*) over (partition by udf_tokenized) as samplecount 
     , udf_chk 
     , max(uniqueid) over (partition by udf_tokenized) as udf_pid 
     from tbl_bil 
    where udf_chk = 'N';  

    type t__pdcsample is table of c_pdcsample%rowtype index by binary_integer; 
    t_pdcsample t__pdcsample; 

begin 

    open c_pdcsample; 
    loop 

     fetch c_pdcsample bulk collect into t_pdcsample limit 1000; 

     exit when t_pdcsample.count = 0; 

     if t_pdcsample.samplecount <> 0 then 
     t_pdcsample.udf_chk := 'y'; 

     if t_pdcsample.samplecount > 1 then 
      t_pdcsample.samplecount := 1; 
     elsif t_pdcsample.samplecount = 1 then 
      t_pdcsample.samplecount := 2; 
     else 
      t_pdcsample.samplecount := 0; 
     end if; 

     end if; 

     forall i in t_pdcsample.first .. t_pdcsample.last 
     update tbl_bil 
      set udfsamplecount = t_pdcsample.samplecount 
       , udf_sampleflag = t_pdcsample.sampleflag 
       , udf_pidspend = null 
       , udf_pid = t_pdcsample.udf_pid 
      where rowid = t_pdcsample(i).rowid 
       ; 

     for i in t_pdcsample.first .. t_pdcsample.last loop 
     update tbl_bil TBL_BIL 
      set udfmatchpercent = 1 
      where uniqueid <> t_pdcsample.uniqueid 
      and udf_tokenized = t_pdcsample.udf_tokenized; 
     end loop; 

     commit ; 

    end loop; 
    close c_pdcsample; 

end PrcdrClustering; 
/

最后呼吁所有表tbl_...有点不必要。

+0

你提出了很多好的观点。但特别是第9点,也不建议使用单个SQL语句阻止我执行+1。 – 2012-02-19 07:41:41

+0

@RobvanWijk,如果你看看逻辑,我认为单个SQL语句是不可能的。我试图把它弄到那么远,但最后的更新阻止了我:-)。 – Ben 2012-02-19 10:37:46

+0

请看我的答案,看看这可以在SQL语句中完成。 – 2012-02-19 14:10:24

4

这是一个使用单个SQL语句的变体。我并不是100%确定逻辑完全一样,但对于我的测试集来说,它是这样的。同样,当前过程不确定性当你有udf_chk =“N”和相同udf_tokenized多个记录......

这是重构的过程

SQL> create procedure prcdr_clustering_refactored 
    2 is 
    3 begin 
    4 merge into tbl_bil t 
    5 using (select tb1.uniqueid 
    6     , count(*) over (partition by tb1.udf_tokenized) cnt 
    7     , max(decode(udf_chk,'N',uniqueid)) over (partition by tb1.udf_tokenized order by tb1.udf_chk) pid 
    8    from tbl_bil tb1 
    9    where udf_chk = 'N' 
10    or exists 
11     (select 'dummy' 
12      from tbl_bil tb2 
13      where tb2.udf_tokenized = tb1.udf_tokenized 
14     ) 
15   ) q 
16  on (t.uniqueid = q.uniqueid) 
17  when matched then 
18   update 
19    set t.udf_samplecount = decode(t.udf_chk,'N',q.cnt,t.udf_samplecount) 
20    , t.udf_sampleflag = decode(t.udf_chk,'N',decode(q.cnt,1,2,1),t.udf_sampleflag) 
21    , t.udf_pid = q.pid 
22    , t.udf_pidspend = decode(t.udf_chk,'N',null,t.udf_pidspend) 
23    , t.udf_matchpercent = decode(t.udf_chk,'N',t.udf_matchpercent,1) 
24    , t.udf_chk = 'Y' 
25 ; 
26 end; 
27/

Procedure created. 

,这里是一个测试:

SQL> select * 
    2 from tbl_bil 
    3 order by uniqueid 
    4/

UNIQUEID VENDORNAME SHORTTEXT SPENDAMT UDF_TOKENI UDF_PID UDF_SAMPLEFLAG UDF_SAMPLECOUNT UDF_MATCHPERCENT UDF_TOKENCNT UDF_PIDSPEND U 
-------- ---------- ---------- -------- ---------- ------- -------------- --------------- ---------------- ------------ ------------ - 
     1 a   a     1 bl    0    0    0    0   0   0 N 
     2 a   a     1 bla    0    0    0    0   0   0 N 
     3 a   a     1 bla    0    0    0    0   0   0 Y 
     4 a   a     1 bla    0    0    0    0   0   0 Y 
     5 a   a     1 bla    0    0    0    0   0   0 Y 
     6 a   a     1 blah    0    0    0    0   0   0 N 
     7 a   a     1 blah    0    0    0    0   0   0 Y 
     8 a   a     1 blah    0    0    0    0   0   0 Y 
     9 a   a     1 blah    0    0    0    0   0   0 Y 
     10 a   a     1 blah    0    0    0    0   0   0 Y 
     11 a   a     1 blah    0    0    0    0   0   0 Y 

11 rows selected. 

SQL> exec prcdr_clustering 

PL/SQL procedure successfully completed. 

SQL> select * 
    2 from tbl_bil 
    3 order by uniqueid 
    4/

UNIQUEID VENDORNAME SHORTTEXT SPENDAMT UDF_TOKENI UDF_PID UDF_SAMPLEFLAG UDF_SAMPLECOUNT UDF_MATCHPERCENT UDF_TOKENCNT UDF_PIDSPEND U 
-------- ---------- ---------- -------- ---------- ------- -------------- --------------- ---------------- ------------ ------------ - 
     1 a   a     1 bl    1    2    1    0   0    Y 
     2 a   a     1 bla    2    1    4    0   0    Y 
     3 a   a     1 bla    2    0    0    1   0   0 Y 
     4 a   a     1 bla    2    0    0    1   0   0 Y 
     5 a   a     1 bla    2    0    0    1   0   0 Y 
     6 a   a     1 blah    6    1    6    0   0    Y 
     7 a   a     1 blah    6    0    0    1   0   0 Y 
     8 a   a     1 blah    6    0    0    1   0   0 Y 
     9 a   a     1 blah    6    0    0    1   0   0 Y 
     10 a   a     1 blah    6    0    0    1   0   0 Y 
     11 a   a     1 blah    6    0    0    1   0   0 Y 

11 rows selected. 

SQL> rollback 
    2/

Rollback complete. 

SQL> exec prcdr_clustering_refactored 

PL/SQL procedure successfully completed. 

SQL> select * 
    2 from tbl_bil 
    3 order by uniqueid 
    4/

UNIQUEID VENDORNAME SHORTTEXT SPENDAMT UDF_TOKENI UDF_PID UDF_SAMPLEFLAG UDF_SAMPLECOUNT UDF_MATCHPERCENT UDF_TOKENCNT UDF_PIDSPEND U 
-------- ---------- ---------- -------- ---------- ------- -------------- --------------- ---------------- ------------ ------------ - 
     1 a   a     1 bl    1    2    1    0   0    Y 
     2 a   a     1 bla    2    1    4    0   0    Y 
     3 a   a     1 bla    2    0    0    1   0   0 Y 
     4 a   a     1 bla    2    0    0    1   0   0 Y 
     5 a   a     1 bla    2    0    0    1   0   0 Y 
     6 a   a     1 blah    6    1    6    0   0    Y 
     7 a   a     1 blah    6    0    0    1   0   0 Y 
     8 a   a     1 blah    6    0    0    1   0   0 Y 
     9 a   a     1 blah    6    0    0    1   0   0 Y 
     10 a   a     1 blah    6    0    0    1   0   0 Y 
     11 a   a     1 blah    6    0    0    1   0   0 Y 

11 rows selected. 

Regards,
Rob。

+0

即使你打扰了,你也应该得到+1,但我认为你已经用了'或存在......虚拟......'我没有考虑过这样做。 – Ben 2012-02-19 14:51:58

相关问题