2013-06-26 103 views
0

昨天我注意到了一个非常有趣的(也是意想不到的)事情。我得到了一个任务(在生产环境中),通过获取dummytable中的所有值来更新TableA的三列(由于某些显而易见的原因,我正在更改表和列的名称)。这两个表的主键都是A列。我知道这个任务非常简单,可以通过多种方式完成,但我选择编写一个存储过程(如下所示)。MySql过程产生错误结果

当存储过程完成执行时,注意到列B,C & statusCode具有相同的值(即,成千上万条记录在这三列中具有相同的值)。有人能告诉我哪里出了问题吗?

1)这个存储过程有什么问题(或缺失)? (Dummy table也有成千上万的记录) 2)除了创建存储过程之外,完成此任务的最佳方式是什么?

PS:我在使用MySQL工作台的生产环境中创建(执行了这个存储过程),并且在过程的执行过程中出现了一个异常:“与MySQL服务器失去连接”,但我猜想自从我运行在远程计算机上执行此过程时,在执行过程时服务器上没有中断。

这是我的存储过程。

DELIMITER $$ 

CREATE DEFINER=`ABC`@`%` PROCEDURE `RetrieveExtractionData`() 

BEGIN 

DECLARE claimlisttraversed BOOLEAN DEFAULT FALSE; 

DECLARE a VARCHAR(20); 

DECLARE b INTEGER; 

DECLARE c INTEGER; 


DECLARE claimlist CURSOR FOR SELECT 
`dummytable`.`A`, 
`dummytable`.`B`, 
`dummytable`.`C` 
FROM `ABC`.`dummytable`; 

DECLARE CONTINUE HANDLER FOR NOT FOUND SET claimlisttraversed = TRUE; 


OPEN claimlist; 

claimlistloop: LOOP 

    FETCH claimlist INTO a, b, c; 

    IF claimlisttraversed THEN 
     CLOSE claimlist; 
     LEAVE claimlistloop; 
    END IF; 
    UPDATE `ABC`.`TableA` 
SET 
`B` = b, 
`C` = c, 
`statuscode` = 'Sent' 
WHERE `A` = a; 

END LOOP claimlistloop; 

END 

回答

1

关于第一个问题:

1)什么是错的,或者没有在这个存储过程? (虚表有 成千上万的记录以及)

我想你忘了CLOSECURSOR。在您结束LOOP之后,您应该CLOSECURSOR

END LOOP claimlistloop; 

CLOSE claimlist; 

END 

2)什么能完成这个任务比其他 创建存储过程的最佳方法是什么?

这样做在STORED PROCEDURE应该没问题。而且使用CURSOR会很好,因为您只需执行一次程序(我猜是因为这是一个生产修复程序)。

但是从您的问题来看,您只是想根据提供的DummyTable更新TableA。我假设这些表具有相同的列。

所以我觉得这个查询比CURSOR更好:

UPDATE TableA A 
    INNER JOIN DummyTable D ON D.A = A.A 
    SET A.B = D.B 
     , A.C = D.C 
     , A.statuscode = 'Sent'; 

但请先尝试在备份或虚拟表。我还没有测试过。

1

忘记光标。事实上,如果可以避免的话,你永远不应该使用游标。游标非常慢。

根本就

UPDATE 
yourTable yt 
INNER JOIN dummyTable dt ON yt.A = dt.A 
SET 
yt.B = dt.B, 
yt.C = dt.C; 

和你的罚款。

+0

感谢您的回复,但您能否解释为什么在这个特殊情况下光标会变慢? –

+0

不仅在这个特殊的例子中,它们总是**缓慢。解释为什么会过深入源代码。但光标首先会读取整个虚拟表格并将其保存在内存中。然后逐行执行更新语句。而使用简单的更新语句读取两个表的部分内容,并将一些指向内存地址的指针交换并写回到磁盘。非常快。 – fancyPants

1

1)这个存储过程有什么问题(或缺失)? (虚拟表 也有数千条记录)
2)除了创建存储过程之外,可能最好的 执行此任务的方式是什么?

恕我直言,你目前失踪的最重要的事情是,你不需要任何游标。您的整个存储过程是一个UPDATE声明。单独执行,或在存储过程中

CREATE PROCEDURE RetrieveExtractionData() 
UPDATE TableA a JOIN dummytable d 
    ON a.a = d.a 
    SET a.b = d.b, a.c = d.c, a.statuscode = 'Sent'; 

你甚至都不需要改变一个分隔符,使用BEGIN ... END

这里是SQLFiddle演示包裹。

+0

不错。谢谢peterm。 :) 由于KaeL首先回答了问题,因此表示接受了他的回答。 –