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