トリガーからストアドプロシージャを呼び出す


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 ;

参考までに、ストアドプロシージャを大幅に簡略化しましたが、問題なく機能することはわかっています。

私ができるようにしたいのは、このように動作する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/en/stored-program-restrictions.html

どんなアイデアでも役に立ちます。


したがって、上記のストアドプロシージャが呼び出される際の問題は、名前にハイフンが含まれているという事実であることがわかりました。ストアドプロシージャ名をsp_set_comment_countに変更すると、問題が解決しました。
マークD

回答:


24

トリガー内からストアドプロシージャを呼び出してはならない大きな理由があります。

トリガーは、本質的にストアドプロシージャです。彼らの行動を巻き戻すのは事実上難しいです。基礎となるすべてのテーブルがInnoDBである場合でも、比例した量の共有行ロックが発生し、排他的な行ロックからの迷惑な断続性が発生します。トリガーが、トリガーへの各呼び出し内でヘビーデューティーMVCCを実行するために停滞しているINSERTおよびUPDATEを使用してテーブルを操作している場合、そのようなケースになります。

トリガーにはオーバーヘッドが必要であることを忘れないでください。実際、MySQLストアドプロシージャプログラミングによると、256ページの「Trigger Overhead」という見出しの下には次のように書かれています。

必然的に、トリガーは適用されるDMLステートメントにオーバーヘッドを追加することを覚えておくことが重要です。実際のオーバーヘッドの量はトリガーの性質によって異なりますが、---すべてのMySQLトリガーがFOR EACH ROWを実行するため---大量の行を処理するステートメントのオーバーヘッドが急速に蓄積する可能性があります。したがって、高価なSQLステートメントや手続き型コードをトリガーに配置することは避けてください。

トリガーオーバーヘッドの詳細な説明は、529〜531ページに記載されています。そのセクションの最後のポイントは次のことを述べています。

ここでの教訓は次のとおりです。トリガーコードはDMLステートメントの影響を受けるすべての行に対して1回実行されるため、トリガーはDMLパフォーマンスの最も重要な要因になりやすくなります。トリガー本体内のコードは、可能な限り軽量である必要があります。特に、トリガー内のSQLステートメントは、可能な限りインデックスによってサポートされる必要があります。

以前の投稿で、トリガーのその他の厄介な側面について説明しました。

概要

MySQLで許可されている場合でも、トリガーからストアドプロシージャを呼び出さないことを強くお勧めします。MySQL 5.5の現在の制限を確認してください


おもしろい、ありがとう。環境にトランザクションクエリがないため、トランザクションの問題が軽減されます。ただし、オーバーヘッドを累積するというアイデアは高く評価できます。この変更の結果が何であるかを確認するために、しばらくdbを見ると思います。
マークD

トリガーをストアドプロシージャと統合するのは正確ではないと思います。少なくとも、ストアドプロシージャでトランザクションを開始してコミットすることは有効です。MySQLは、トリガーで同じことをしようとすると文句を言います。これはばかげています。なぜなら、何らかの変更に応じて1つまたは複数のテーブルをトランザクションで更新する必要があるトリガーを使用することは、完全に有効なユースケースであり、簡単にサポートする必要があるためです。
アロス14年

だから私はこのトリガーを持っています、それは本当に大きいです。挿入時と更新時の両方で、テーブルに対していくつかの計算を実行します。Mysqlのトリガーは、複雑な場合、本当に痛くなることがあります。トリガーをプロシージャに分割する方がはるかに簡単です。
ラマー

8

それで、これが数時間私を悩ませた問題であると信じるかどうかがわかります。

sp_set-comment_countというプロシージャを簡単に定義できます。ただし、上記のプロシージャを呼び出すと、同じようには機能しません。

CALL sp_set-comment_count(これは、サーバーが-をマイナスとして解釈するためだと推測できます)。

以来、アンダースコアのみを使用するようにストアドプロシージャ名を変更しましたが、すべて解決したようです。


後期パーティーにしかし:あなたは同様に他の場所でそれを参照する必要がありますので、その名前に特殊文字を許可引用識別子を使用して、あなたのSPを作成している: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を呼び出したときにエラーをスローし続けたということであったようです。
マークD

1

後のカンマACは構文エラーのようです:

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

有効なポイントではなく、私は単純にそのクエリからのいくつかの余分なセットをトリミングし、この場合のエラーの実際の原因は、削除するのを忘れて、
マーク・D
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.