Chiamare una procedura memorizzata da un trigger


17

Ho creato una procedura memorizzata in mysql usando la sintassi seguente.

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 ;

Cordiali saluti Ho semplificato notevolmente la procedura memorizzata, ma so che funziona senza problemi.

Quello che mi piacerebbe poter fare è impostare un trigger da usergroup_comments che funzioni in questo modo.

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;

Ma per qualche motivo ogni volta che lo faccio mysql mi lancia un errore che è poco utile affermando che c'è un errore di sintassi nella riga 4.

Ho esaminato la documentazione di mysql e ho trovato alcune informazioni sulle restrizioni dei trigger, ma l'ho trovato abbastanza contorto.

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

Qualsiasi idea sarebbe utile.


Quindi si scopre che il problema con la procedura memorizzata sopra chiamata era il fatto che aveva un trattino nel suo nome. La modifica del nome della procedura memorizzata in sp_set_comment_count ha risolto il problema.
Mark D,

Risposte:


24

C'è un ottimo motivo per cui non dovresti mai chiamare le procedure memorizzate dai trigger.

I trigger sono, per natura, procedure memorizzate. Le loro azioni sono praticamente difficili da ripristinare . Anche se tutte le tabelle sottostanti sono InnoDB, si verificherà un volume proporzionale di blocchi di riga condivisi e fastidiose intermittenze da blocchi di riga esclusivi. Questo sarebbe il caso se i trigger manipolassero le tabelle con INSERT e UPDATE stagnati per eseguire MVCC heavy duty all'interno di ogni chiamata a un trigger .

Non dimenticare che i trigger richiedono overhead. Infatti, secondo MySQL Stored Procedure Programming , la pagina 256 sotto il titolo "Trigger Overhead" dice quanto segue:

È importante ricordare che, per necessità, i trigger aggiungono un sovraccarico all'istruzione DML a cui si applicano. la quantità effettiva di overhead dipenderà dalla natura del trigger, ma --- poiché tutti i trigger MySQL vengono eseguiti PER OGNI FILA --- l'overhead può accumularsi rapidamente per le istruzioni che elaborano un numero elevato di righe. Dovresti quindi evitare di inserire costose istruzioni SQL o codici procedurali nei trigger.

Una spiegazione estesa del sovraccarico del trigger è riportata alle pagine 529-531. Il punto conclusivo di quella sezione afferma quanto segue:

La lezione qui è questa: poiché il codice trigger verrà eseguito una volta per ogni riga interessata da un'istruzione DML, il trigger può facilmente diventare il fattore più significativo nelle prestazioni DML. Il codice all'interno del corpo del trigger deve essere il più leggero possibile e, in particolare, tutte le istruzioni SQL nel trigger devono essere supportate da indici ogni volta che è possibile.

Ho spiegato altri aspetti negativi di Trigger in un post precedente.

SOMMARIO

Consiglio vivamente di non chiamare alcuna procedura memorizzata da un trigger , anche se MySQL lo consente. Dovresti dare un'occhiata alle attuali restrizioni per MySQL 5.5 .


Interessante, grazie per il testa a testa. La mancanza di query transazionali nel nostro ambiente mitiga il problema delle transazioni. Tuttavia, posso apprezzare l'idea di accumulare spese generali. Immagino che guarderò il db per un po 'per vedere quale sia il risultato di questo cambiamento.
Mark D,

Non credo sia corretto confondere i trigger con le stored procedure. Come minimo, è valido per avviare e eseguire il commit di una transazione in una procedura memorizzata. MySQL si lamenta se si tenta di fare lo stesso in un trigger. Il che è sciocco, perché avere un trigger che deve aggiornare in modo transazionale una o più tabelle in risposta ad alcune modifiche è un caso d'uso completamente valido che dovrebbe essere supportato in modo semplice.
aroth

Quindi ho questo grilletto, è davvero grande. Esegue diversi calcoli sulla mia tabella, sia al momento dell'inserimento che dell'aggiornamento. I trigger in Mysql possono davvero diventare dolorosi quando sono complessi. Sarebbe molto più facile scomporre il grilletto in procedure.
Lamar,

8

Quindi si scopre che questo è il problema che mi ha afflitto per qualche ora, che ci crediate o no.

Posso facilmente definire una procedura chiamata sp_set-comment_count. Tuttavia, quando si chiama detta procedura, non funziona allo stesso modo.

CALL sp_set-comment_count (posso solo supporre che ciò sia dovuto al fatto che il server interpreta il - come meno).

Da allora ho cambiato il nome della procedura memorizzata per usare solo caratteri di sottolineatura e sembra aver risolto tutto.


In ritardo alla festa ma: hai creato il tuo SP usando un identificatore citato, che ha permesso caratteri speciali nel suo nome, quindi dovresti fare riferimento in modo simile altrove:CALL `sp-set-comment_count`(NEW.`gid`);
mustaccio

5

Se dice di errore di sintassi, molto probabilmente ti sei dimenticato di cambiare delimitatore (come hai fatto per la procedura memorizzata). Quindi hai bisogno

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

Grazie, questo in realtà mi ha fatto pensare sulla strada giusta. In effetti il ​​mio sp era chiamato sp-set_comment_count. Quando viene chiamato da un trigger, sembra che il problema fosse che quando si chiamava SP dal trigger, si continuava a lanciare l'errore.
Mark D,

1

Sembra che la virgola dopo ACsia un errore di sintassi:

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

Punto valido, ma non la vera causa dell'errore in questo caso ho semplicemente ritagliato alcuni set extra da quella query e ho dimenticato di rimuovere il,
Mark D
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.