Как правильно зациклить в хранимой функции в MySQL?

У меня возникли некоторые трудности с правильным написанием довольно простой хранимой процедуры. Рассмотрим следующий фрагмент таблицы статьи:

id    replaced_by     baseID
 1              2          0
 2              3          0
 3              0          0

Простая иерархическая таблица, использующая копирование при записи. Когда статья редактируется, в поле replace_by текущей статьи устанавливается идентификатор ее новой копии.

Я добавил поле 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 ;

Это кажется достаточно простым, пока я не вызову функцию, используя:

SELECT getBaseID(3);

Я ожидал, что функция вернет 1 Я даже хочу понять, что это может занять долю секунды. Вместо этого процессор машины загружается на 100% (mysqld).

Я даже переписал ту же функцию, используя REPEAT .. UNTIL и с WHILE .. DO , с тот же конечный результат.

Кто-нибудь может объяснить, почему мой процессор загружается на 100%, когда он входит в цикл?

Примечание: я просто пытаюсь выиграть время. Я создал точно такую ​​же функцию в PHP, которая работает нормально, но мы предполагаем, что MySQL может сделать это немного быстрее. Нам нужно просмотреть около 18 миллионов записей. Любое сэкономленное время, которое я смогу сэкономить, того стоит.

Заранее спасибо за любую помощь и / или указатели.


Решенный 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 ;
8
задан djBo 14 August 2011 в 11:32
поделиться