트리거에서 스토어드 프로 시저 호출


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로 변경하면 문제가 해결되었습니다.
Mark D

답변:


24

트리거 내에서 저장 프로 시저를 호출해서는 안되는 큰 이유가 있습니다.

트리거는 본질적으로 저장 프로 시저입니다. 그들의 행동은 사실상 롤백하기 어렵다 . 모든 기본 테이블이 InnoDB 인 경우에도 비례적인 볼륨의 공유 행 잠금과 배타적 행 잠금으로 인한 성가신 간헐성이 발생합니다. 트리거가 INSERT와 UPDATE로 테이블을 조작 하고 트리거를 호출 할 때마다 무거운 MVCC 를 수행하도록 정체되어 있는 경우가 여기에 해당합니다 .

트리거에는 오버 헤드가 필요하다는 것을 잊지 마십시오. 실제로 MySQL Stored Procedure Programming 에 따르면 "Trigger Overhead"헤드 아래의 256 페이지에 다음과 같이 나와 있습니다.

필요에 따라 트리거가 적용되는 DML 문에 오버 헤드가 추가된다는 점을 기억해야합니다. 실제 오버 헤드 양은 트리거의 특성에 따라 달라 지지만 모든 MySQL 트리거가 각 행을 실행함에 따라 많은 행을 처리하는 명령문에 대해 오버 헤드가 빠르게 누적 될 수 있습니다. 따라서 값 비싼 SQL 문 또는 절차 코드를 트리거에 배치하지 마십시오.

트리거 오버 헤드에 대한 자세한 설명은 529-531 페이지에 나와 있습니다. 이 섹션의 결론은 다음과 같습니다.

여기서 교훈은 다음과 같습니다. 트리거 코드는 DML 문의 영향을받는 모든 행마다 한 번씩 실행되므로 트리거는 DML 성능에서 가장 중요한 요소가 될 수 있습니다. 트리거 본문 내부의 코드는 가능한 한 가벼워 야하며, 특히 트리거의 모든 SQL 문은 가능할 때마다 인덱스에서 지원해야합니다.

이전 게시물에서 트리거의 다른 불쾌한 측면을 설명했습니다.

요약

나는 것이 강하게 트리거에서 모든 저장 프로 시저를 호출하지 않는 것이 좋습니다 MySQL이 그것을 허용하더라도. MySQL 5.5에 대한 현재 제한 사항을 확인하십시오 .


흥미 롭습니다. 감사합니다. 우리 환경에 트랜잭션 쿼리가 없으면 트랜잭션 문제가 완화됩니다. 그러나 오버 헤드를 축적한다는 아이디어를 이해할 수 있습니다. 나는이 변경의 결과가 무엇인지 알기 위해 db를 잠시 동안 볼 것이라고 생각합니다.
Mark D

트리거를 저장 프로 시저와 연결하는 것이 정확하지 않다고 생각합니다. 최소한 저장 프로 시저에서 트랜잭션을 시작하고 커밋하는 것이 유효합니다. 트리거에서 동일한 작업을 시도하면 MySQL이 불평합니다. 일부 변경에 응답하여 하나 이상의 테이블을 트랜잭션 방식으로 업데이트해야하는 트리거를 갖는 것은 간단한 방식으로 지원되어야하는 완전히 유효한 유스 케이스이기 때문에 어리 석습니다.
aroth

저는이 방아쇠를 가지고 있습니다. 정말 큽니다. 삽입 및 업데이트시 테이블에서 여러 가지 계산을 수행합니다. Mysql의 트리거는 복잡 할 때 실제로 고통 스러울 수 있습니다. 트리거를 절차로 나누는 것이 훨씬 쉽습니다.
Lamar

8

그래서 이것이 몇 시간 동안 나를 괴롭히는 문제라고 믿습니다.

sp_set-comment_count라는 프로 시저를 쉽게 정의 할 수 있습니다. 그러나 해당 절차를 호출하면 같은 방식으로 작동하지 않습니다.

CALL sp_set-comment_count (서버가-를 마이너스로 해석하기 때문이라고 가정 할 수 있습니다).

그 후 저장 프로 시저 이름을 밑줄 만 사용하도록 변경했으며 모든 것이 해결 된 것 같습니다.


파티에 CALL `sp-set-comment_count`(NEW.`gid`);
늦었지만

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를 호출 할 때 오류가 계속 발생하는 것으로 보입니다.
Mark D

1

쉼표 뒤 AC의 구문 오류는 다음과 같습니다.

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

유효한 점이지만이 경우 오류의 실제 원인은 아닙니다. 해당 쿼리에서 일부 추가 세트를
Mark D
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.