Appeler une procédure stockée à partir d'un déclencheur

17

J'ai créé une procédure stockée dans mysql en utilisant la syntaxe suivante.

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 ;

Pour info j'ai considérablement simplifié la procédure stockée mais je sais que cela fonctionne sans aucun problème.

Ce que j'aimerais pouvoir faire, c'est configurer un déclencheur à partir de usergroup_comments qui fonctionne comme ceci.

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;

Mais pour une raison quelconque, chaque fois que je fais, mysql me lance une erreur qui n'est pas utile en déclarant qu'il y a une erreur de syntaxe à la ligne 4.

J'ai parcouru la documentation mysql et trouvé quelques informations sur les restrictions des déclencheurs mais je l'ai trouvée assez compliquée.

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

Toutes les idées seraient utiles.

Mark D
la source
Il s'avère donc que le problème avec la procédure stockée ci-dessus appelée était le fait qu'elle avait un trait d'union dans son nom. La modification du nom de la procédure stockée en sp_set_comment_count a résolu le problème.
Mark D

Réponses:

24

Il y a une bonne raison pour laquelle vous ne devez jamais appeler des procédures stockées à partir de déclencheurs.

Les déclencheurs sont, par nature, des procédures stockées. Leurs actions sont pratiquement difficiles à annuler . Même si toutes les tables sous-jacentes sont InnoDB, vous rencontrerez un volume proportionnel de verrous de ligne partagés et une intermittence gênante de verrous de ligne exclusifs. Ce serait le cas si les déclencheurs manipulaient des tables avec des INSERT et des UPDATE stagnant pour effectuer un MVCC robuste à l'intérieur de chaque appel à un déclencheur .

N'oubliez pas que les déclencheurs nécessitent des frais généraux. En fait, selon MySQL Stored Procedure Programming , page 256 sous la rubrique "Trigger Overhead" dit ce qui suit:

Il est important de se rappeler que, par nécessité, les déclencheurs ajoutent une surcharge à l'instruction DML à laquelle ils s'appliquent. la quantité réelle de surcharge dépendra de la nature du déclencheur, mais --- comme tous les déclencheurs MySQL s'exécutent POUR CHAQUE RANG --- la surcharge peut rapidement s'accumuler pour les instructions qui traitent un grand nombre de lignes. Vous devez donc éviter de placer des instructions SQL ou du code procédural coûteux dans les déclencheurs.

Une explication détaillée de la surcharge de déclenchement est donnée aux pages 529-531. Le point de conclusion de cette section indique ce qui suit:

La leçon à tirer est la suivante: puisque le code de déclenchement s'exécutera une fois pour chaque ligne affectée par une instruction DML, le déclencheur peut facilement devenir le facteur le plus important des performances DML. Le code à l'intérieur du corps du déclencheur doit être aussi léger que possible et - en particulier - toutes les instructions SQL dans le déclencheur doivent être prises en charge par des index chaque fois que possible.

J'ai expliqué d'autres aspects désagréables des déclencheurs dans un post précédent.

SOMMAIRE

Je recommande fortement de ne pas appeler de procédures stockées à partir d'un déclencheur , même si MySQL le permet. Vous devriez vérifier les restrictions actuelles pour MySQL 5.5 .

RolandoMySQLDBA
la source
Intéressant, merci pour l'avertissement. L'absence de requêtes transactionnelles dans notre environnement atténue le problème de transaction. Cependant, je peux apprécier l'idée d'accumuler des frais généraux. Je suppose que je vais regarder la base de données pendant un certain temps pour voir quel est le résultat de ce changement.
Mark D
Je ne pense pas qu'il soit exact de confondre les déclencheurs avec les procédures stockées. Au minimum, il est valide pour démarrer et valider une transaction dans une procédure stockée. MySQL se plaint si vous essayez de faire de même dans un déclencheur. Ce qui est stupide, car avoir un déclencheur qui doit mettre à jour transactionnellement une ou plusieurs tables en réponse à un changement est un cas d'utilisation entièrement valide qui devrait être pris en charge de manière simple.
aroth
J'ai donc ce déclencheur, c'est vraiment gros. Il effectue plusieurs calculs sur ma table, à la fois lors de l'insertion et de la mise à jour. Les déclencheurs dans Mysql peuvent vraiment devenir douloureux lorsqu'ils sont complexes. Il serait beaucoup plus facile de décomposer le déclencheur en procédures.
Lamar
8

Il s'avère donc que c'est le problème qui m'a tourmenté pendant quelques heures, croyez-le ou non.

Je peux facilement définir une procédure appelée sp_set-comment_count. Cependant, lors de l'appel de ladite procédure, cela ne fonctionne pas de la même manière.

APPELER sp_set-comment_count (je peux seulement supposer que c'est parce que le serveur interprète le - comme un moins).

J'ai depuis changé le nom de la procédure stockée pour n'utiliser que des traits de soulignement et il semble avoir tout résolu.

Mark D
la source
Tard dans la soirée mais: vous avez créé votre SP en utilisant un identifiant cité, qui a permis des caractères spéciaux dans son nom, vous devez donc le référencer de la même manière ailleurs:CALL `sp-set-comment_count`(NEW.`gid`);
mustaccio
5

S'il indique une erreur de syntaxe, il est fort probable que vous ayez oublié de modifier le délimiteur (comme vous l'avez fait pour la procédure stockée). Vous avez donc besoin

DELIMITER $$
CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
FOR EACH ROW
BEGIN
   CALL sp_set_count(NEW.`gid`);
END;
$$
a1ex07
la source
Merci, cela m'a fait réfléchir sur la bonne voie. En fait, mon sp s'appelait sp-set_comment_count. Lorsqu'il est appelé par un déclencheur, il semble que le problème était que lors de l'appel du SP à partir du déclencheur, le - continuait de lancer l'erreur.
Mark D
1

On dirait que la virgule après ACest une erreur de syntaxe:

UPDATE usergroups
   SET allCount = AC,
 WHERE ........
user22800
la source
Point valide, mais pas la cause réelle de l'erreur dans ce cas, j'ai simplement supprimé certains ensembles supplémentaires de cette requête et oublié de supprimer le,
Mark D