Chapitre 1013 minAvancé
Événement planifié MySQL : CREATE EVENT et event_scheduler
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- vérifier que le planificateur d'événements tourne ;
- créer un événement ponctuel ou récurrent ;
- surveiller, désactiver et supprimer un événement ;
- choisir entre un événement MySQL et une tâche cron.
4 exercices corrigés
Un événement MySQL est un programme stocké que le serveur exécute tout seul à une date précise ou à intervalle régulier, sans qu'aucun client soit connecté : c'est une tâche planifiée interne à la base, comme une ligne de cron. On le crée avec CREATE EVENT … ON SCHEDULE … DO …, et il est exécuté par le planificateur d'événements (event_scheduler). Ce chapitre l'utilise pour purger les traces anciennes et calculer des statistiques mensuelles sur la base parc.
Le planificateur d'événements
Les événements sont lancés par un processus du serveur, le planificateur, réglé par la variable event_scheduler :
SHOW VARIABLES LIKE 'event_scheduler'; -- ON
| Valeur | Effet |
|---|---|
ON | Le planificateur tourne et exécute les événements. Valeur par défaut de MySQL 8.4 |
OFF | Arrêté : aucun événement ne s'exécute. Se change à chaud avec SET GLOBAL event_scheduler = ON; |
DISABLED | Désactivé au démarrage du serveur : ne peut pas être changé sans redémarrer |
Quand il tourne, le planificateur apparaît dans SHOW PROCESSLIST comme un utilisateur event_scheduler, avec l'état Waiting for next activation.
CREATE EVENT
CREATE EVENT [IF NOT EXISTS] nom_evenement
ON SCHEDULE { AT horodatage | EVERY intervalle [STARTS horodatage] [ENDS horodatage] }
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON REPLICA]
[COMMENT 'texte']
DO instruction; -- ou un bloc BEGIN … END
AT: une seule exécution, à la date donnée.AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR: dans une heure.EVERY: une exécution récurrente,EVERY 1 DAY,EVERY 1 MONTH,EVERY 15 MINUTE…STARTSfixe la première exécution (donc l'heure des suivantes),ENDSla dernière possible.ON COMPLETION NOT PRESERVE(par défaut) : un événement terminé (leATpassé, ou leENDSatteint) est supprimé automatiquement.PRESERVEle garde, désactivé, pour garder la trace de sa définition.DISABLE ON REPLICA: sur un serveur répliqué, l'événement ne s'exécute que sur le serveur source, pas sur les copies, qui reçoivent déjà ses effets par la réplication.
Créer un événement demande le privilège EVENT sur la base. Comme un trigger, un événement s'exécute avec les droits de son propriétaire (DEFINER), dans une connexion qui lui est propre : les variables de session d'un client n'y existent pas.
Purger les traces anciennes
Les tables d'audit du chapitre 9 grandissent sans fin, et elles contiennent des données personnelles : le RGPD impose une durée de conservation, que Sorbier Logistique fixe à un an. Chaque nuit à 3 heures, un événement supprime les traces plus anciennes :
DELIMITER //
CREATE EVENT ev_purge_audit
ON SCHEDULE EVERY 1 DAY STARTS '2026-11-09 03:00:00'
COMMENT 'Durée de conservation des traces : 1 an'
DO
BEGIN
DELETE FROM audit_ticket WHERE modifie_le < NOW() - INTERVAL 1 YEAR;
DELETE FROM historique_affectation WHERE modifie_le < NOW() - INTERVAL 1 YEAR;
END //
DELIMITER ;
Le corps d'un événement suit les règles d'une procédure : BEGIN … END, variables, conditions, gestionnaires d'erreurs, et donc DELIMITER dans le client mysql. La durée de conservation choisie se documente dans le registre des traitements : c'est elle qu'un contrôle de la CNIL demanderait.
Calculer des statistiques chaque mois
Le responsable veut, chaque mois, le nombre de tickets ouverts, de tickets résolus et le temps passé du mois précédent. Le calcul va dans une procédure, que l'événement appelle : la procédure se teste et se rejoue à la main, l'événement ne fait que la planifier. Les chiffres affichés supposent la base remise à zéro au début du chapitre (voir L'essentiel) : une intervention ajoutée en essayant les exemples d'un chapitre précédent les change.
DELIMITER //
CREATE PROCEDURE calculer_stat_mois(IN p_debut DATE)
BEGIN
DECLARE v_fin DATE DEFAULT p_debut + INTERVAL 1 MONTH;
REPLACE INTO stat_mensuelle (mois, nb_ouverts, nb_resolus, minutes_passees, calcule_le)
SELECT DATE_FORMAT(p_debut, '%Y-%m'),
(SELECT COUNT(*) FROM ticket
WHERE date_ouverture >= p_debut AND date_ouverture < v_fin),
(SELECT COUNT(*) FROM ticket
WHERE date_cloture >= p_debut AND date_cloture < v_fin),
(SELECT COALESCE(SUM(duree_min), 0) FROM intervention
WHERE date_intervention >= p_debut AND date_intervention < v_fin),
NOW();
END //
DELIMITER ;
CALL calculer_stat_mois('2026-09-01');
CALL calculer_stat_mois('2026-10-01');
SELECT mois, nb_ouverts, nb_resolus, minutes_passees FROM stat_mensuelle ORDER BY mois;
| mois | nb_ouverts | nb_resolus | minutes_passees |
|---|---|---|---|
| 2026-09 | 6 | 4 | 370 |
| 2026-10 | 7 | 3 | 825 |
REPLACE INTO remplace la ligne du mois si elle existe déjà (même clé primaire) : rejouer le calcul ne crée pas de doublon. Les bornes >= début et < fin comptent chaque date une fois, quelle que soit l'heure. L'événement, le 1er de chaque mois à 1 heure :
CREATE EVENT ev_stat_mensuelle
ON SCHEDULE EVERY 1 MONTH STARTS '2026-12-01 01:00:00'
COMMENT 'Indicateurs du mois précédent'
DO CALL calculer_stat_mois(DATE_FORMAT(CURDATE() - INTERVAL 1 MONTH, '%Y-%m-01'));
Le 1er décembre 2026, CURDATE() - INTERVAL 1 MONTH donne le 1er novembre, et DATE_FORMAT(…, '%Y-%m-01') le premier jour de ce mois : la procédure calcule novembre. Un corps d'une seule instruction n'a pas besoin de DELIMITER.
Un événement ponctuel, pour finir : relever la priorité du ticket 14 dans une heure s'il n'est toujours pas traité.
CREATE EVENT ev_rappel_ticket_14
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO UPDATE ticket SET priorite = 'haute' WHERE id_ticket = 14 AND statut = 'ouvert';
Après son exécution, il disparaît (ON COMPLETION NOT PRESERVE).
Surveiller, modifier, supprimer
SHOW EVENTS FROM parc;
SELECT event_name, status, event_type, interval_value, interval_field, starts, last_executed
FROM information_schema.events
WHERE event_schema = 'parc'
ORDER BY event_name;
| EVENT_NAME | STATUS | EVENT_TYPE | INTERVAL_VALUE | INTERVAL_FIELD | STARTS | LAST_EXECUTED |
|---|---|---|---|---|---|---|
| ev_purge_audit | ENABLED | RECURRING | 1 | DAY | 2026-11-09 03:00:00 | NULL |
| ev_rappel_ticket_14 | ENABLED | ONE TIME | NULL | NULL | NULL | NULL |
| ev_stat_mensuelle | ENABLED | RECURRING | 1 | MONTH | 2026-12-01 01:00:00 | NULL |
LAST_EXECUTED vaut NULL tant que l'événement n'a jamais tourné : c'est la colonne à surveiller. Pour modifier un événement, ALTER EVENT accepte toutes les clauses de CREATE EVENT :
ALTER EVENT ev_purge_audit DISABLE; -- suspendre
ALTER EVENT ev_purge_audit ENABLE; -- reprendre
ALTER EVENT ev_purge_audit ON SCHEDULE EVERY 1 DAY STARTS '2026-11-09 04:00:00';
DROP EVENT IF EXISTS ev_rappel_ticket_14;
Événement MySQL ou tâche cron ?
| Événement MySQL | Tâche cron (ou Planificateur de tâches Windows) | |
|---|---|---|
| Où vit la tâche | Dans la base : sauvegardée et restaurée avec elle | Sur un serveur, dans la table crontab d'un compte |
| Ce qu'elle peut faire | Du SQL seulement | N'importe quel programme : script, sauvegarde, envoi de courriel |
| Accès | Aucun mot de passe à stocker | Un compte MySQL et son mot de passe dans un fichier de configuration |
| Suivi des erreurs | Journal d'erreurs du serveur MySQL | Sortie du script, courriel de cron, journaux système |
Un événement convient à une tâche purement SQL sur la base : purge, statistiques, archivage d'une table dans une autre. Une sauvegarde avec mysqldump, un export de fichier ou une tâche qui touche d'autres serveurs reste une tâche cron (automatiser les sauvegardes ; planifier une tâche sous Linux).
Exercices
Exercice 1 sur 4 Purger le journal des erreurs Réussi À revoir
Écris un événement ev_purge_erreurs qui supprime chaque dimanche à 2 heures les lignes de journal_erreur de plus de 90 jours, à partir du dimanche 15 novembre 2026. Comment vérifies-tu ensuite qu'il est bien planifié ?
Voir la réponseMasquer la réponse de l'exercice 1
CREATE EVENT ev_purge_erreurs
ON SCHEDULE EVERY 1 WEEK STARTS '2026-11-15 02:00:00'
COMMENT 'Conservation des erreurs : 90 jours'
DO DELETE FROM journal_erreur WHERE survenue_le < NOW() - INTERVAL 90 DAY;
EVERY 1 WEEK à partir d'un dimanche à 2 heures donne tous les dimanches à 2 heures. Pour vérifier : SHOW VARIABLES LIKE 'event_scheduler'; doit répondre ON, et SELECT status, starts FROM information_schema.events WHERE event_name = 'ev_purge_erreurs'; doit montrer ENABLED et la bonne date. Après le premier dimanche, last_executed doit être renseigné.
Tu avais trouvé ?
Exercice 2 sur 4 Relancer chaque lundi Réussi À revoir
Planifie la procédure relancer_tickets du chapitre 5 pour qu'elle s'exécute chaque lundi à 7 heures, sur les tickets ouverts depuis plus de 14 jours, à partir du lundi 9 novembre 2026. La procédure a un paramètre OUT : comment l'appeler dans un événement ?
Voir la réponseMasquer la réponse de l'exercice 2
CREATE EVENT ev_relance_hebdo
ON SCHEDULE EVERY 1 WEEK STARTS '2026-11-09 07:00:00'
DO CALL relancer_tickets(NOW(), 14, @nb_relances);
Un paramètre OUT demande une variable : une variable de session @nb_relances convient. Elle appartient à la connexion de l'événement et disparaît avec elle, ce qui est sans conséquence ici. Pour garder le nombre de relances, la procédure (ou un bloc BEGIN … END dans l'événement) l'écrirait dans une table.
Tu avais trouvé ?
Exercice 3 sur 4 L'événement qui ne fait rien Réussi À revoir
Un stagiaire a créé cet événement sur un serveur MariaDB 11.4 le 10 novembre 2026 à 14 heures. Le lendemain, rien ne s'est passé et l'événement a disparu. Donne deux causes possibles.
CREATE EVENT ev_archive
ON SCHEDULE AT '2026-11-10 13:00:00'
DO INSERT INTO ticket_archive SELECT * FROM ticket WHERE statut = 'resolu';
Voir la réponseMasquer la réponse de l'exercice 3
- La date est déjà passée au moment de la création (13 h, alors qu'il est 14 h). Le serveur accepte l'instruction avec une simple note (1588,
Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.) : l'événement est supprimé aussitôt, sans s'exécuter. C'est pourquoi il a « disparu ». - Le planificateur est arrêté : sur MariaDB,
event_schedulervautOFFpar défaut. Même avec une date future, l'événement ne se serait pas exécuté.
On peut ajouter que la table ticket_archive doit exister et avoir les mêmes colonnes que ticket, et qu'un archivage digne de ce nom supprimerait ensuite les tickets copiés, dans une transaction, ce qui demande une procédure.
Tu avais trouvé ?
Exercice 4 sur 4 Événement ou cron ? Réussi À revoir
Pour chaque tâche, choisis un événement MySQL ou une tâche cron, et justifie en une phrase : (1) une sauvegarde quotidienne de la base parc copiée sur le NAS ; (2) la clôture automatique des tickets résolus depuis plus de 30 jours ; (3) l'envoi par courriel du rapport mensuel ; (4) la mise à jour chaque heure d'une table de synthèse des licences.
Voir la réponseMasquer la réponse de l'exercice 4
cron:mysqldumpest un programme externe, et la copie vers le NAS touche un autre serveur.- Événement : une requête SQL sur la base, sans rien d'extérieur. (Dans
parc, un ticket résolu est déjà clos : la tâche serait plutôt l'archivage des tickets résolus.) cron: MySQL ne sait pas envoyer de courriel. Le script lit les chiffres, éventuellement calculés par un événement dansstat_mensuelle, et envoie le message.- Événement : du SQL pur, qui vit avec la base.
Tu avais trouvé ?