如何在MySQL上正确循环存储函数?

djB*_*jBo 8 mysql loops stored-functions

我很难获得一个非常简单的存储过程.请考虑以下文章表格片段:

id    replaced_by     baseID
 1              2          0
 2              3          0
 3              0          0
Run Code Online (Sandbox Code Playgroud)

一个简单的分层表,使用copy-on-write.编辑文章时,当前文章的replacement_by字段将设置为其新副本的ID.

我添加了一个baseID字段,将来应该存储一篇文章的baseID.在上面的例子中,有一篇文章(例如id 3).它的baseID是1.

为了获取baseID,我创建了以下存储过程:

DELIMITER $$

CREATE FUNCTION getBaseID(articleID INT) RETURNS INT
BEGIN
    DECLARE x INT;
    DECLARE y INT;
    SET x = articleID;
    sloop:LOOP
        SELECT id INTO y FROM article WHERE replaced_by_articleID = x;
        IF y IS NOT NULL THEN
            SET x = y;
            ITERATE sloop;
        ELSE
            LEAVE sloop;
        END IF;  
    END LOOP;
    RETURN x;
END $$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

这看起来很简单,直到我实际调用函数使用:

SELECT getBaseID(3);
Run Code Online (Sandbox Code Playgroud)

我希望,函数返回1.我甚至愿意理解它可能需要一秒钟.相反,机器的CPU上升到100%(mysqld).

我甚REPEAT .. UNTIL至用WHILE .. DO相同的最终结果重写了相同的函数.

任何人都可以解释为什么我的CPU在进入循环时会上升100%?

旁注:我想简单地赢得时间.我已经在PHP中创建了完全相同的函数,它执行得很好,但我们猜测MySQL可以稍微快一些.我们需要筛选大约1800万条记录.我可以节省的任何时间都值得.

提前感谢任何帮助和/或指示.


解决了SQL:

DELIMITER $$

CREATE FUNCTION getBaseID(articleID INT) RETURNS INT
BEGIN
    DECLARE x INT;
    DECLARE y INT;
    SET x = articleID;
    sloop:LOOP
        SET y = NULL;
        SELECT id INTO y FROM article WHERE replaced_by_articleID = x;
        IF y IS NULL THEN
            LEAVE sloop;
        END IF;  
        SET x = y;
        ITERATE sloop;
    END LOOP;
    RETURN x;
END $$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

a1e*_*x07 2

来自mysql

如果查询没有返回行,则会出现错误代码 1329 的警告(无数据),并且变量值保持不变

因此,当没有找到给定的记录xy保持不变)时,您将陷入无限循环,请尝试SET y = (SELECT id ....)改为或在 select 语句之前添加SET y = null(它应该是循环中的第一个语句)