【问题标题】:MySql Procedure Producing Wrong ResultsMySql 过程产生错误的结果
【发布时间】:2013-06-26 16:17:28
【问题描述】:

昨天我注意到一件非常有趣(也出乎意料)的事情。我被赋予了一项任务(在生产环境中),通过获取 dummytable 中存在的所有值来更新 TableA 的三列(由于一些明显的原因,我正在更改表和列名)。两个表的主键都是 A 列。我知道这个任务非常简单,可以通过多种方式完成,但我选择为此编写一个存储过程(如下所示)。

当存储过程完成执行时,注意到 B、C 和 statusCode 列具有相同的值(即数千条记录在这三列中具有相同的值)。有人可以告诉我出了什么问题吗?

1) 这个存储过程有什么问题(或遗漏)? (虚拟表也有数千条记录) 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

【问题讨论】:

    标签: mysql sql stored-procedures


    【解决方案1】:

    第一个问题:

    1) 这个存储过程有什么问题(或遗漏)? (虚拟表有 数千条记录)

    我猜你忘了CLOSECURSOR。在你结束LOOP 之后,你应该CLOSE CURSOR

    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';
    

    但请先在备用或虚拟桌子上尝试。我还没有测试过。

    【讨论】:

      【解决方案2】:

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

      简单的做

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

      你很好。

      【讨论】:

      • 感谢您的回复,但您能解释一下为什么在这种特殊情况下光标会变慢吗?
      • 不仅在这种特殊情况下,它们总是慢得要命。解释为什么会深入到源代码。但是光标会首先读取整个虚拟表并将其保存在内存中。然后逐行执行更新语句。而通过简单的更新语句,两个表的部分都被读取,一些指向内存地址的指针被交换并写回磁盘。速度极快。
      【解决方案3】:

      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 演示。

      【讨论】:

      • 不错。谢谢彼得。 :) 因为 KaeL 先回答了这个问题,所以标记他的回答被接受了。
      猜你喜欢
      • 1970-01-01
      • 2015-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多