Викличте збережену процедуру з тригера


17

Я створив збережену процедуру в mysql, використовуючи наступний синтаксис.

DROP PROCEDURE IF EXISTS `sp-set_comment_count`;

DELIMITER $$

CREATE PROCEDURE `sp_set-comment_count` (IN _id INT)
BEGIN
   -- AC   - AllCount
   DECLARE AC INT DEFAULT 0;

   SELECT COUNT(*) AS ac
     INTO AC
     FROM usergroups AS ug
LEFT JOIN usergroup_comments AS ugm ON ugm.`gid` = ug.`id`
LEFT JOIN mediagallery AS dm ON ugm.mid = dm.`id`
    WHERE dm.`status` NOT IN (200, 201, 202, 203, 204, 205)
      AND ug.`id` = _id;

   UPDATE usergroups
      SET allCount = AC,
    WHERE usergroups.`id` = _id;

END $$
DELIMITER ;

FYI Я значно спростив збережену процедуру, але я знаю, що вона працює без проблем.

Що я хотів би зробити, це встановити тригер від usergroup_comments, який працює так.

DROP TRIGGER IF EXISTS `usergroups_comments_insert` 

CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
    FOR EACH ROW
    BEGIN
       CALL sp-set-comment_count(NEW.`gid`);
    END;

Але чомусь кожен раз, коли я роблю mysql, видає на мене помилку, що є менш ніж корисною заявою, що в рядку 4 є синтаксична помилка.

Я прочесав документацію mysql і знайшов деяку інформацію про обмеження триггерів, але виявив, що вона доволі вивернута.

http://dev.mysql.com/doc/refman/5.1/uk/stored-program-restrictions.html

Будь-які ідеї були б корисні.


Тож виявляється, що проблема з названою вище збереженою процедурою викликала те, що в її імені був дефіс. Зміна збереженої назви процедури на sp_set_comment_count вирішила проблему.
Марк D

Відповіді:


24

Є велика причина, чому ви ніколи не слід викликати збережені процедури зсередини тригерів.

Тригери за своєю природою є збереженими процедурами. Їх дії практично важко відкотити . Навіть якщо всі основні таблиці є InnoDB, ви відчуєте пропорційний об'єм блокувань спільних рядків та дратівливої ​​переривчастість від ексклюзивних блоків рядків. Так може бути, якби тригери маніпулювали таблицями з INSERT та UPDATE, які перебували в застою, щоб виконувати MVCC з важким режимом всередині кожного виклику до тригера .

Не забувайте, що тригери вимагають накладних витрат. Насправді, відповідно до програмування збережених процедур MySQL , на сторінці 256 під заголовком "Тригер накладних витрат" зазначено наступне:

Важливо пам’ятати, що, за необхідності, тригери додають накладні витрати до оператора DML, до якого вони застосовуються. фактична кількість накладних витрат буде залежати від характеру тригера, але --- оскільки всі тригери MySQL виконуються ДЛЯ КОЖОГО РОЗУМУ - накладні витрати можуть швидко накопичуватися для операторів, які обробляють велику кількість рядків. Тому слід уникати розміщення будь-яких дорогих операторів SQL або процедурного коду в тригерах.

Розширене пояснення накладних тригерів наведено на сторінках 529-531. Заключний пункт із цього розділу визначає наступне:

Урок ось такий: оскільки код тригера буде виконуватися один раз для кожної рядки, на яку впливає оператор DML, тригер може стати найважливішим фактором продуктивності DML. Код всередині корпусу тригера повинен бути максимально легким і, зокрема - будь-які оператори SQL у тригері, коли це можливо, підтримуватимуться індексами.

Я пояснив інші неприємні аспекти Тригерів у попередньому пості.

ПІДСУМОК

Я настійно рекомендую не викликати жодних збережених процедур із тригера , навіть якщо MySQL дозволяє. Вам слід перевірити поточні обмеження для MySQL 5.5 .


Цікаво, дякую за голови вгору. Відсутність запитів транзакцій у нашому середовищі пом'якшує проблему транзакцій. Однак я можу оцінити ідею накопичення накладних витрат. Я думаю, я деякий час буду дивитися на db, щоб побачити, що є результатом цієї зміни.
Марк D

Я не думаю, що правильно поєднувати тригери із збереженими процедурами. Як мінімум, можна запустити та здійснити транзакцію у збереженій процедурі. MySQL скаржиться, якщо ви спробуєте зробити те ж саме в тригері. Що нерозумно, тому що наявність тригера, який потребує транзакційного оновлення однієї чи декількох таблиць у відповідь на певну зміну, є цілком коректним випадком використання, який слід підтримувати прямо.
aroth

Тож у мене є цей спусковий механізм, який дійсно великий. Він виконує кілька обчислень на моєму столі, як після вставки, так і оновлення. Тригери в Mysql дійсно можуть стати болючими, коли вони складні. Було б набагато простіше розбити тригер на процедури.
Ламар

8

Тож виявляється, це питання, яке мучило мене протягом декількох годин, вірю чи ні.

Я можу легко визначити процедуру, що називається, sp_set-comment_count. Однак при виклику зазначеної процедури це працює не так.

CALL sp_set-comment_count (Я можу припустити, що це лише тому, що сервер інтерпретує - як мінус).

З тих пір я змінив назву збереженої процедури, щоб використовувати лише підкреслення, і, здається, усе вирішило.


Пізно до партії, але: ви створили свій ІП за допомогою цитованого ідентифікатора, який дозволив спеціальним символам в його імені, тому вам слід посилатися на нього аналогічно в іншому місці:CALL `sp-set-comment_count`(NEW.`gid`);
mustaccio

5

Якщо це говорить про синтаксичну помилку, швидше за все, ви забули змінити роздільник (як це було зроблено для збереженої процедури). Тож вам потрібно

DELIMITER $$
CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
FOR EACH ROW
BEGIN
   CALL sp_set_count(NEW.`gid`);
END;
$$

Дякую, що це насправді змусило мене думати по правильному шляху. Насправді мій sp називався sp-set_comment_count. При виклику тригера виявляється, що проблема викликала те, що при виклику SP з тригера помилка продовжувала кидати.
Марк Д

1

Схоже, кома після AC- це синтаксична помилка:

UPDATE usergroups
   SET allCount = AC,
 WHERE ........

Дійсна точка, але не фактична причина помилки в цьому випадку, я просто обрізав кілька додаткових наборів із цього запиту і забув видалити,
Марк D
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.