У меня возникли некоторые затруднения с получением довольно простой правильной хранимой процедуры.Рассмотрим следующий фрагмент таблицы статей:
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 ;