Wywołaj procedurę przechowywaną z wyzwalacza

17

Utworzyłem procedurę przechowywaną w mysql przy użyciu następującej składni.

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 ;

Do waszej informacji znacznie uprościłem procedurę przechowywaną, ale wiem, że działa ona bez żadnych problemów.

To, co chciałbym móc zrobić, to skonfigurować wyzwalacz z usergroup_comments, który działa w ten sposób.

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;

Ale z jakiegoś powodu za każdym razem, gdy robię, mysql rzuca we mnie błędem, który jest mniej niż pomocny, stwierdzając, że w wierszu 4 występuje błąd składniowy.

Przeczesałem dokumentację mysql i znalazłem informacje o ograniczeniach wyzwalaczy, ale okazało się, że są dość skomplikowane.

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

Wszelkie pomysły byłyby pomocne.

Mark D.
źródło
Okazuje się więc, że problem z wywołaniem powyższej procedury składowanej polegał na tym, że w nazwie miał łącznik. Zmiana nazwy procedury składowanej na sp_set_comment_count rozwiązała problem.
Mark D

Odpowiedzi:

24

Jest wielki powód, dla którego nigdy nie należy wywoływać procedur przechowywanych z poziomu wyzwalaczy.

Wyzwalacze są z natury procedurami przechowywanymi. Ich działania są praktycznie trudne do wycofania . Nawet jeśli wszystkie tabele bazowe to InnoDB, doświadczysz proporcjonalnej ilości współdzielonych blokad wierszy i denerwujących przerw z wyłącznych blokad wierszy. Tak by się stało, gdyby wyzwalacze manipulowały tabelami z INSERTami i UPDATEMI w stagnacji, aby wykonać MVCC o dużej wytrzymałości wewnątrz każdego wywołania wyzwalacza .

Nie zapominaj, że wyzwalacze wymagają narzutu. W rzeczywistości, zgodnie z programowaniem procedur przechowywanych MySQL , strona 256 pod nagłówkiem „Trigger Overhead” mówi:

Ważne jest, aby pamiętać, że z konieczności wyzwalacze powodują dodatkowe obciążenie instrukcji DML, do której się odnoszą. faktyczna wielkość narzutu będzie zależeć od natury wyzwalacza, ale --- ponieważ wszystkie wyzwalacze MySQL wykonują DLA KAŻDEGO WIERSZA --- narzut może szybko kumulować się dla instrukcji przetwarzających dużą liczbę wierszy. Dlatego należy unikać umieszczania kosztownych instrukcji SQL lub kodu proceduralnego w wyzwalaczach.

Rozszerzone objaśnienie narzutu na spust podano na stronach 529-531. Punkt końcowy z tej sekcji brzmi następująco:

Lekcja jest następująca: ponieważ kod wyzwalacza będzie wykonywany raz dla każdego wiersza objętego instrukcją DML, wyzwalacz może łatwo stać się najbardziej znaczącym czynnikiem w wydajności DML. Kod w ciele wyzwalacza musi być jak najlżejszy, a w szczególności wszelkie instrukcje SQL w wyzwalaczu powinny być obsługiwane przez indeksy, gdy tylko jest to możliwe.

Wyjaśniłem inne nieprzyjemne aspekty Triggerów we wcześniejszym poście.

STRESZCZENIE

Chciałbym gorąco polecam nie nazywając żadnych procedur przechowywanych z wyzwalaczem , nawet jeśli MySQL pozwala. Powinieneś zapoznać się z aktualnymi ograniczeniami dla MySQL 5.5 .

RolandoMySQLDBA
źródło
Ciekawe, dziękuję za zgłoszenie się. Brak zapytań transakcyjnych w naszym środowisku ogranicza problem z transakcją. Mogę jednak docenić pomysł akumulacji kosztów ogólnych. Chyba obejrzę db przez chwilę, aby zobaczyć, jaki jest rezultat tej zmiany.
Mark D
Nie sądzę, aby połączenie wyzwalaczy z procedurami przechowywanymi było poprawne. Przynajmniej można rozpocząć i zatwierdzić transakcję w procedurze składowanej. MySQL narzeka, jeśli spróbujesz zrobić to samo w wyzwalaczu. Co jest głupie, ponieważ posiadanie wyzwalacza, który musi transakcyjnie aktualizować jedną lub więcej tabel w odpowiedzi na jakąś zmianę, jest całkowicie prawidłowym przypadkiem użycia, który powinien być obsługiwany w prosty sposób.
aroth
Więc mam ten wyzwalacz, który jest naprawdę duży. Wykonuje kilka obliczeń na moim stole, zarówno po wstawieniu, jak i aktualizacji. Wyzwalacze w MySQL mogą naprawdę stać się bolesne, gdy są złożone. Znacznie łatwiej byłoby rozbić spust na procedury.
Lamar,
8

Okazuje się, że to problem, który nękał mnie przez kilka godzin, wierzcie lub nie.

Mogę łatwo zdefiniować procedurę o nazwie sp_set-comment_count. Jednak wywoływanie wspomnianej procedury nie działa w ten sam sposób.

ZADZWOŃ sp_set-comment_count (mogę tylko założyć, że to dlatego, że serwer interpretuje - jako minus).

Od tego czasu zmieniłem nazwę procedury składowanej, aby używać tylko znaków podkreślenia i wygląda na to, że wszystko rozwiązało.

Mark D.
źródło
Późno na imprezę, ale: utworzyłeś SP za pomocą cytowanego identyfikatora, który pozwalał na znaki specjalne w jego nazwie, więc powinieneś odwoływać się do niego w innym miejscu:CALL `sp-set-comment_count`(NEW.`gid`);
mustaccio
5

Jeśli mówi o błędzie składni, najprawdopodobniej zapomniałeś zmienić ogranicznik (tak jak w przypadku procedury składowanej). Więc potrzebujesz

DELIMITER $$
CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
FOR EACH ROW
BEGIN
   CALL sp_set_count(NEW.`gid`);
END;
$$
a1ex07
źródło
Dziękuję, że tak naprawdę pomyślałem o właściwej ścieżce. W rzeczywistości mój sp nazywał się sp-set_comment_count. Gdy wywoływany jest przez wyzwalacz, wydaje się, że problem polegał na tym, że po wywołaniu SP z wyzwalacza - ciągle zgłaszał błąd.
Mark D
1

Wygląda na to, że przecinek po ACjest błędem składni:

UPDATE usergroups
   SET allCount = AC,
 WHERE ........
użytkownik22800
źródło
Ważny punkt, ale nie rzeczywista przyczyna błędu w tym przypadku po prostu przyciąłem kilka dodatkowych zestawów z tego zapytania i zapomniałem usunąć
Mark D