DB2存储过程中LOAD CURSOR 使用

经过反反复复几天的折腾,终于搞定了一个DB2的存储过程,真是不容易啊,感慨DB2做开发,咋就这么困难呢?

记录下个人的经历:

           1、目的:

 需要通过创建一个存储过程,对一个数据量较大的表(千万级)进行数据统计,将统计之后的数据放入到另外一张 临时表中,待其它操作处理。


           2、实现思路:

思路其实很简单,在sql server下核心sql 不过就是 insert 。。。select。。


          3、实现过程:

    1)、按照sql server下原有的思路,书写存储过程,由于表名非固定,因此需要用到动态sql。

 源码如下:

[c-sharp]  view plain  copy
  1. CREATE PROCEDURE proc_AggregateUrlVisit (in StrStartTime varchar(50), in StrEndTime varchar(50), in TempTableName varchar(50))  
  2. LANGUAGE SQL   
  3. BEGIN   
  4. DECLARE SqlStr varchar(4000);   
  5. --若存在临时表,则将临时表删除   
  6. call proc_DropTable('behavesa', TempTableName);   
  7. --根据表名创建表  
  8. SET SqlStr = 'CREATE TABLE behavesa.' || TempTableName ||' (userid varchar(50), urlinfo varchar(700) , visitnum int, urlid int GENERATED ALWAYS AS IDENTITY ) NOT LOGGED INITIALLY ';  
  9. EXECUTE IMMEDIATE SqlStr;  
  10.  --插入数据统计后信息   
  11. SET SqlStr = 'insert into behavesa.' || TempTableName || '(userid , urlinfo , visitnum) select userid, urlinfo, sum (visitnum) as visitnum from behavesa.UserUrlLog where starttime >= ''' || StrStartTime || ''' and endtime < ''' || StrEndTime || ''' group by userid, urlinfo' ;   
  12. EXECUTE IMMEDIATE SqlStr;  
  13. END@  
 

 

执行是没有问题的,可关键是周6下午执行,到了周1早上发现还在执行。。。疯掉。

搜集了下资料发现,insert 动态sql的时候会对每次插入进行日志,因此性能较低。而提高性能的建议则是用load 来代替insert。因此进行第2种方法操作。

 

2)、load方法有两种,一种是export。。。load;另一种则是load 。。。cursor。


通过试验sql语句 发现export ..load 可以执行,而且速度也很快,但却有个不足,需要将数据先export到本地磁盘,然后方可进行load。

如果数据量小,问题不大,但对于本系统,数据动辄上亿行,而千万行就多达6,7百兆,因此舍弃该方式。

 

而第二种load。。。cursor是完全可以使用的,核心sql为:

 

declare staffcursor cursor for select userid, urlinfo, sum(visitnum) as visitnum

--省略wherefrom behavesa.UserUrlLog group by userid, urlinfo ;

 

load from staffcursor of cursor insert into behavesa.temptable;

 

测试发现执行时间约为17分钟左右(笔记本性能不咋地)。

于是采用load 。。。cursor方式修改存储过程,代码如下:

[c-sharp]  view plain  copy
  1. CREATE PROCEDURE proc_AggregateUrlVisit (in StrStartTime varchar(50), in StrEndTime varchar(50), in TempTableName varchar(50))   
  2. LANGUAGE SQL   
  3. BEGIN   
  4. DECLARE SqlStr varchar(4000);   
  5. --若存在临时表,则将临时表删除 call beahvesa.proc_DropTable('behavesa', TempTableName);  
  6. --根据表名创建表   
  7. SET SqlStr = 'CREATE TABLE behavesa.' || TempTableName ||' (userid varchar(50), urlinfo varchar(700) , visitnum int, urlid int GENERATED ALWAYS AS IDENTITY ) NOT LOGGED INITIALLY in userspace1';   
  8. EXECUTE IMMEDIATE SqlStr;  
  9. --插入数据统计后信息   
  10. SET SqlStr = 'declare staffcursor cursor for select userid, urlinfo, sum(visitnum) as visitnum from behavesa.UserUrlLog where starttime >= ''' || StrStartTime || ''' and endtime < ''' || StrEndTime || ''' group by userid, urlinfo ; load from staffcursor of cursor insert into behavesa.' || TempTableName ||';';   
  11. EXECUTE IMMEDIATE SqlStr;   
  12. END@  

  

  db2 -td@ -f test.db2,没有问题,可以执行,但执行

      db2 call proc_AggregateUrlVisit ('2009-02-01 00:00:01','2009-04-01 00:00:01', 'temptable')

      则会报错:

   SQL0104N  在 "01' group by userid," 后面找到异常标记 "urlinfo ;  load from
   staffcursor of curso"。预期标记可能包括:"<space>"。  SQLSTATE=42601


怎么修改也死活过不去,一开始怀疑是动态sql的问题,查资料发现有资料说

“execute  immediate只能执行DML语句!”,因此试验了下,直接在存储过程中load。。。cursor,发现也不成整半天,存储过程中是不支持LOAD的。。。。


    3)、借助 SYSPROC.ADMIN_CMD 实现

       没办法了。。。于是查资料吧,嘿,发现原来可以借助系统存储过程 SYSPROC.ADMIN_CMD 来实现的。主要sql如下:

        CALL SYSPROC.ADMIN_CMD ('load from (select userid, urlinfo, sum(visitnum) as visitnum 

        from UserUrlLog where starttime >= StrStartTime and EndTime <= StrEndTime
        group by userid, urlinfo ) of cursor insert into HttplogTempTable');

         按此思路继续进行修改存储过程,发现本机可以哦~没问题(db2版本为DB2 Express-C 9.5)。

    4)、借助 sysproc.db2load 实现

       折腾了半天,以为可以了,于是将写好的存储过程移到服务器上,由于版权问题服务器版本为 "DB2 企业服务器版8.2",

编译不过去了。。。。

错误信息:

 DB21034E  该命令被当作 SQL语句来处理,因为它不是有效的“命令行处理器”命令。在 SQL 处理期间,它返回:SQL0440N  未找到类型为 "PROCEDURE" 命名为 "SYSPROC.ADMIN_CMD"
且具有兼容自变量的已授权例程。  LINE NUMBER=7.  SQLSTATE=42884

郁闷啊,通过控制中心查找ADMIN_CMD存储过程,嘿嘿,真的没有哦,搜吧,整半天,从8.2版本以后才开始支持该存储过程的,怪不得呢。继续查资料吧(估计公司的监控会显示我最近访问网页数量过多哦~~)。

解决办法:1)、更新fix包 ;  2)寻找其它替代方式。

害怕fix后影响版权相关,而且也嫌麻烦,所以就找到了db2load的方法,更改后的存储过程为:

[c-sharp]  view plain  copy
  1. CREATE PROCEDURE proc_AggregateUrlVisit (in StrStartTime varchar(50), in StrEndTime varchar(50) , in TempTableName varchar(100))   
  2. LANGUAGE SQL   
  3. BEGIN   
  4. declare SqlStr varchar(500);  
  5. declare v_version_number INTEGER default 1;  
  6. declare v_cursor_statement VARCHAR(32672);  
  7. declare v_load_command VARCHAR(32672);  
  8. declare v_sqlcode INTEGER default -1;  
  9. declare v_sqlmessage VARCHAR(2048) default '';  
  10. declare v_rows_read BIGINT default -1 ;  
  11. declare v_rows_skipped BIGINT default -1;  
  12. declare v_rows_loaded BIGINT default -1;  
  13. declare v_rows_rejected BIGINT default -1;  
  14. declare v_rows_deleted BIGINT default -1;  
  15. declare v_rows_committed BIGINT default -1;  
  16. declare v_rows_part_read BIGINT default -1;  
  17. declare v_rows_part_rejected BIGINT default -1;  
  18. declare v_rows_part_partitioned BIGINT default -1;  
  19. declare v_mpp_load_summary VARCHAR(32672) default NULL;  
  20. --若存在临时表,则将临时表删除  
  21. call proc_DropTable('behavesa', TempTableName);  
  22. --根据表名创建表  
  23. SET SqlStr = 'CREATE TABLE behavesa.' || TempTableName ||' (userid varchar(50), urlinfo varchar(700)  
  24. , visitnum int, urlid int GENERATED ALWAYS AS IDENTITY ) NOT   LOGGED   INITIALLY ';  
  25. EXECUTE IMMEDIATE SqlStr;  
  26. --更改表附加方式  
  27. SET SqlStr = 'ALTER TABLE ' || TempTableName || ' APPEND ON';  
  28. EXECUTE IMMEDIATE SqlStr;  
  29. --调用DB2LOAD,进行select cursor 插入数据统计后的信息  
  30. CALL sysproc.db2load ( v_version_number, 'declare cur cursor  
  31. for select userid, urlinfo, sum(visitnum) as visitnum  from UserUrlLog  
  32. where starttime >= ''' || StrStartTime || ''' and endtime < ''' || StrEndtime  
  33. || '''group by userid, urlinfo ',  
  34. 'load from cur of cursor modified by norowwarnings insert into ' || TempTableName,  
  35. v_sqlcode, v_sqlmessage, v_rows_read, v_rows_skipped,  
  36. v_rows_loaded, v_rows_rejected, v_rows_deleted, v_rows_committed,  
  37. v_rows_part_read, v_rows_part_rejected,  
  38. v_rows_part_partitioned, v_mpp_load_summary) ;  
  39. END@  

  oh,搞定了。。。呵呵,终于见到阳光了。。难为死我了。

 但是db2load那些参数都是啥作用呢?查Reference 文档没查到。。只能大概揣测了。


参考网址:

    http://www.itpub.net/thread-936984-1-1.html

    http://www.db2china.net/?viewnews-2142.html

    http://topic.csdn.net/u/20071216/19/aad3c957-e4cb-4aab-9d52-414a7a6cf32f.html

    http://bytes.com/groups/ibm-db2/478049-calling-sysproc-db2load-within-sql-stored-procedure

    http://topic.csdn.net/u/20070416/15/4285e1e8-6693-46d0-9912-5c87781e7fa0.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值