Работа с событиями и расписаниями: 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;
Скрыть рекламу навсегда

📘 VK Видео — обучение без ограничений

Все уроки доступны без VPN, без блокировок и зависаний.

Можно смотреть с телефона, планшета или компьютера — в любое время.

▶️ Смотреть на VK Видео