业务比较复杂的情况下使用游标

来源:互联网 发布:淘宝网店如何找上家 编辑:程序博客网 时间:2024/05/01 08:38

    前段时间在客户那封闭开发,要在数据库中做一个自动“裁货”的功能。

    于是就写了一个存储过程,由于业务比较复杂,一张SO首先要通过备货合同分配库存,然后通过实际可用库存进行分配,再用在途的PO数量分配,最后用非在途的PO进行分配,所以每条SO要单独处理,于是就用到了游标。

    哗啦哗啦,一千多行代码写完了,于是就在数据库中测试,问题一个一个的排除了,然后就把该功能放到程序中,让客户测试,几天过去了,偶尔会有一些小问题,总体效果还行,慢慢完善后运行的时间也从之前的6分多钟变到了后面的2分多钟,最好的情况是不到一分钟就搞定了,相对于老大之前提的10分钟之内这一要求来说,还是让人比较满意的。

    客户也比较接受该功能,于是就开始正式试用该功能了,一个多星期过去了,突然有一天客户说,这个“裁货”功能怎么要运行这么久,当时第一感觉是一惊,不会吧!用了那么长时间了,应该不会有这情况吧!然后自己试着运行一下,1分钟过去了,10分钟过去了,30分钟过去了,实在忍受不了了,这时的感觉是有死循环了。于是创造条件进行排查。

   哎!一千多行的代码啊!!!怎么查?搞来搞去,东搞西搞,这搞那搞,大半天时间过去了,也快到忍耐的极限了,finally,发现是在处理在途的PO的时候会出现这样的问题。然后尝试变换不同的条件运行,最后将游标中的一条语句做为重点的怀疑对象。

   于是想确认一下到底这条语句导致的,就在一个测试库中写了如下的代码:

 

IF OBJECT_ID('TB') >0 DROP TABLE TBCREATE TABLE TB(A INT,B VARCHAR(10))GOINSERT INTO TB(A,B)SELECT 1,'A'UNION ALLSELECT 2,'B'UNION ALLSELECT 3,'C'SELECT * FROM TB
--结果:
A   B
1 A2 B3 C
DECLARE @A INT, @B VARCHAR(10)DECLARE CUR CURSOR FOR SELECT A,B FROM TBOPEN CURFETCH NEXT FROM CUR  INTO @A,@BWHILE @@FETCH_STATUS = 0BEGIN PRINT @B
          --一堆处理游标所指的记录的语句
 
          --将游标所指的记录进行拆分,复制出另外一条记录,并插入到游标所处理的表。
INSERT INTO TB (A,B)SELECT @A,@BFETCH NEXT FROM CUR INTO @A,@BENDCLOSE CURDEALLOCATE CUR
 
 
--运行这段代码发现一直在运行,消息框中也一直在输出数据,于是赶紧终止运行,然后再查。
SELECT * FROM TB
 
结果就恐怖了,TB表中多了几万行记录。。。
也就确认了是这个问题导致的。
 
 


现在回过头来看,可能这个问题很简单,但是当时由于游标中的代码太长了,很难注意到这种情况,也就导致了上面提到的情况的发生了。

 

后来通过引入一个物理意义上的临时表来解决了这个问题。

 

DECLARE @A INT, @B VARCHAR(10)DECLARE CUR CURSOR FOR SELECT A,B FROM TBOPEN CURFETCH NEXT FROM CUR  INTO @A,@BWHILE @@FETCH_STATUS = 0BEGIN PRINT @B          --一堆处理游标所指的记录的语句          --将游标所指的记录进行拆分,复制出另外一条记录,并插入到游标所处理的表。--INSERT INTO TB (A,B)--SELECT @A,@B
          INSERT INTO TBTMP(A,B)  --引入的物理意义上的临时表
          SELECT @A,@B         FETCH NEXT FROM CUR INTO @A,@BENDCLOSE CURDEALLOCATE CUR
INSERT INTO TB(A,B)
SELECT A,B FROM TBTMP
 
 

就OK了。

 

谨以此纪念我那无数死去的脑细胞!!!

 

原创粉丝点击