Работа с событиями и расписаниями: Event Scheduler, Jobs
🕒 Введение: Что такое планировщики событий?
Обычный SQL выполняется «здесь и сейчас» — но что, если нужно автоматизировать рутинные задачи? Event Scheduler — это встроенный механизм MySQL/MariaDB для выполнения SQL-кода по расписанию. Он умеет:
- Чистить устаревшие данные раз в сутки
- Делать бэкапы
- Отправлять уведомления
- Обновлять агрегированные отчеты
Работает без внешних скриптов — всё внутри СУБД! Давайте разбираться.
⚙️ Включаем планировщик
Перед началом проверим статус:
SHOW VARIABLES LIKE 'event_scheduler';
Если значение OFF, активируем (требуются права администратора):
SET GLOBAL event_scheduler = ON;
Важно: После перезагрузки сервера настройка сбросится. Для перманентного включения пропишите event_scheduler=ON в my.cnf.
🎯 Создаем первое событие
Допустим, надо ежедневно архивировать старые логи. Вот как это выглядит:
CREATE EVENT archive_old_logs
ON SCHEDULE EVERY 1 DAY STARTS CURRENT_TIMESTAMP
DO
BEGIN
INSERT INTO logs_archive
SELECT * FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY;
DELETE FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY;
END;
Разберем конструкцию:
archive_old_logs— имя событияEVERY 1 DAY— периодичностьSTARTS CURRENT_TIMESTAMP— начало с текущего моментаDO— тело события (может быть многострочным черезBEGIN...END)
⏰ Варианты расписания
Гибкость планировщика поражает! Вот топ-5 сценариев:
1. Раз в минуту в рабочее время
ON SCHEDULE EVERY 1 MINUTE
STARTS '2024-01-01 09:00:00'
ENDS '2024-01-01 18:00:00'
2. По конкретным дням
ON SCHEDULE EVERY 1 WEEK
STARTS '2024-01-01 00:00:00'
ON COMPLETION PRESERVE
3. Однократно
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
4. Комбинированный интервал
ON SCHEDULE EVERY 1 DAY + INTERVAL 3 HOUR
5. Сложное условие через Cron-синтаксис (MariaDB 10.3+)
ON SCHEDULE EVERY '0 22 * * 1-5' -- Каждый будний день в 22:00
🔍 Управление событиями
Просмотр активных событий:
SHOW EVENTS;
Быстрое отключение без удаления:
ALTER EVENT archive_old_logs DISABLE;
Полное удаление:
DROP EVENT archive_old_logs;
Изменение параметров:
ALTER EVENT archive_old_logs
ON SCHEDULE EVERY 2 DAY
COMMENT 'Новый интервал архивации';
💡 Реальные кейсы применения
1. Автоматический ротинг паролей
CREATE EVENT rotate_passwords
ON SCHEDULE EVERY 90 DAY
DO
UPDATE users SET password = SHA2(CONCAT('salt', UUID()), 256)
WHERE last_pwd_change < NOW() - INTERVAL 90 DAY;
2. Ночная агрегация статистики
CREATE EVENT update_metrics
ON SCHEDULE EVERY 1 DAY STARTS '23:00:00'
DO
INSERT INTO daily_stats (date, user_count, revenue)
SELECT
CURRENT_DATE(),
COUNT(*),
SUM(amount)
FROM orders
WHERE created_at >= CURRENT_DATE() - INTERVAL 1 DAY;
3. Оповещение об истекающих подписках
CREATE EVENT check_subscriptions
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
INSERT INTO notifications (user_id, message)
SELECT user_id, 'Подписка истекает через 3 дня!'
FROM subscriptions
WHERE expires_at = CURDATE() + INTERVAL 3 DAY;
END;
⚠️ Ловушки и лучшие практики
1. Логирование — добавьте запись в таблицу-журнал при старте события:
CREATE EVENT safe_event
ON SCHEDULE EVERY 1 DAY
DO
BEGIN
INSERT INTO event_logs (event_name, started_at)
VALUES ('safe_event', NOW());
-- Основная логика здесь
END;
2. Защита от дублей — используйте GET_LOCK():
SELECT GET_LOCK('my_event_lock', 0);
-- Основной код
SELECT RELEASE_LOCK('my_event_lock');
3. Ошибки — обрабатывайте исключения:
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
INSERT INTO errors (event, message)
VALUES ('archive_logs', 'Ошибка архивации');
END;
🚀 Продвинутые фишки
Динамический SQL в событиях:
CREATE EVENT dynamic_query
ON SCHEDULE EVERY 1 DAY
DO
BEGIN
SET @sql = CONCAT('DELETE FROM temp_', YEAR(NOW()), '_', MONTH(NOW()));
PREPARE stmt FROM @sql;
EXECUTE stmt;
END;
Вложенные события — создание новых событий из тела текущего (только для смелых!):
CREATE EVENT self_replicating
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
DO
CREATE EVENT new_event
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO SELECT 1;
📊 Мониторинг и отладка
Проверяйте производительность через системные таблицы:
SELECT * FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT LIKE '%EVENT%';
Анализ истории выполнения:
SELECT * FROM mysql.event_history
WHERE event_name = 'archive_old_logs'
ORDER BY event_started DESC LIMIT 10;
Для глубокого анализа смотрите записи SHOW ENGINE INNODB STATUS после выполнения событий.
🔗 Интеграция с другими технологиями
Хотите больше? Комбинируйте Events с:
- Триггерами для каскадных операций
- Хранимыми процедурами для сложной логики
- Внешними скриптами через
sys_exec()(если настроен)
Пример вызова Python-скрипта:
CREATE EVENT call_python
ON SCHEDULE EVERY 1 DAY
DO
BEGIN
DECLARE result INT;
SET result = sys_exec('python3 /scripts/cleanup.py');
END;