События (events) в MySQL (планировщик заданий аля CRON)
Предисловие
Наверное в 99% случаев если необходимо делать операции над данными в БД использовалась связка PHP и CRONа и в скрипте описывались все необходимые запросы. В MySQL 5.1.6 появился планировщик. Теперь можно не терзая указанную выше связку, если она не требует чего-то больше, что не умеет делать MySQL.
Для работы вам понадобится:
сервер БД 5.1.6 и выше; права пользователю на использование этой фичи.
Проверка работоспособности планировщика
Первое, что надо сделать — это удостоверится, что планировщик включен. Это можно сделать по команде
SHOW VARIABLES LIKE '%event%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | event_scheduler | OFF | +-----------------+-------+
Получается он у меня выключен, ну что же можем включить:
SET GLOBAL event_scheduler = ON;
тем самым мы включили его до перезагрузки сервера!!! Что бы планировщик был постоянно включен необходимо в файле конфигурации поставить параметр: event_scheduler=1.
Теперь придумаем задание для того, что бы на его примере всё пояснить.
ЗАДАНИЕ
Например мы имеем таблицу users и нам каждый день в 00-00 необходимо выбирать всех, кто родился в этот день и записывать данные в табл users_dr (ФИО и пол). Можно конечно обойтись и простой выборкой по текущему дню, но если сайт с высокой нагрузкой, то делать выборку каждый раз это будет смерть БД.
Создание планировщика
Оператор планировщика имеет следующий синтаксис:
CREATE [DEFINER = { user | CURRENT_USER }] EVENT [IF NOT EXISTS] event_name ON SCHEDULE schedule [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] DO sql_statement; schedule: AT timestamp [+ INTERVAL interval] ... | EVERY interval [STARTS timestamp [+ INTERVAL interval] ...] [ENDS timestamp [+ INTERVAL interval] ...] interval: quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
Много букв, но ничего, разберем на нашем примере.
DELIMITER ;; DROP EVENT IF EXISTS `test_user_dr;; CREATE EVENT `test_user_dr` ON SCHEDULE EVERY 1 DAY STARTS '2009-07-19 00:00:00' ON COMPLETION PRESERVE ENABLE COMMENT 'таблица дней рождений' DO BEGIN DROP TABLE IF EXISTS `test`.`users_dr`; CREATE TABLE `test`.`users_dr` SELECT `fio`,`sex` FROM `test`.`users` WHERE `dr`=DATE_FORMAT(NOW(),"%d-%m")=DATE_FORMAT(`dr`,"%d-%m") ORDER BY `fio` ASC; END;; DELIMITER ;
Теперь разберем.
Т.к. в планировщике используется больше одного запроса, то эти запросы необходимо ограничивать директивами BEGIN и END, а для того, что бы MySQL не начал выполнять операции внутри планировщика, нам надо переопределить символ обозначающий конец запроса, по дефолту это ; Оператором DELIMITER ;; мы указываем, что теперь две косые есть конец запроса.
На всякий случай удаляем планировщик DROP EVENT IF EXISTS `test_user_dr` // Создаем новый планировщик `test_user_dr` с параметрами ON SCHEDULE EVERY 1 DAY STARTS ‘2009-07-19 00:00:00’, означает каждый в 00-00-00 начиная с указанной даты, параметр DAY — интервал, может принимать и другие параметры, о них написано выше. Далее говорим ON COMPLETION PRESERVE ENABLE — включаем этот планировщик и если он завершиться ОКОНЧАТЕЛЬНО, то его из памяти не удаляем. Наш планировщик никогда не завершается, т.к. нет директивы ENDS timestamp, но если бы он была и было написано ON COMPLETION NOT PRESERVE, то всё задание удалилось. С комментарием, думаю, все понятно. Далее после слов DO BEGIN идут запросы, которые будут выполняться планировщиком и заканчивает директивой END.
Теперь планировщик будет каждый день начиная с 19 июля 2009 года в полночь делать таблицу пользователей у которых ДР в текущий день.
Удаление планировщика
Тут все просто, используем оператор
DROP EVENT [IF EXISTS] event_name</pre> В нашем случае <pre lang="sql">DROP EVENT IF EXISTS `test_user_dr`;</pre> <h2>Изменение планировщика</h2> <pre lang="sql">ALTER [DEFINER = { user | CURRENT_USER }] EVENT event_name [ON SCHEDULE schedule] [ON COMPLETION [NOT] PRESERVE] [RENAME TO new_event_name] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] [DO sql_statement]
Например надо изменить время срабатывания, ну например чтобы таблицы ДР обновлялась 2 раза в сутки, тогда следует написать
ALTER EVENT `test_user_dr` ON SCHEDULE EVERY 12 HOUR;
Список планировщиков
Список заданий можно посмотреть 2-мя способами:
1-й покажет все данные по всем планировщикам для БД test
SHOW EVENTS FROM `test`\G; *************************** 1. row *************************** Db: test Name: test_user_dr Definer: root@localhost Time zone: SYSTEM Type: RECURRING Execute at: NULL Interval value: 12 Interval field: HOUR Starts: 2009-07-19 00:00:00 Ends: NULL Status: ENABLED Originator: 0 character_set_client: cp1251 collation_connection: cp1251_general_ci Database Collation: cp1251_general_ci 1 row in set (0.00 sec)
2-й Показывает полностью данные для указанного задания
SHOW CREATE EVENT `test_user_dr`\G; *************************** 1. row *************************** Event: test_user_dr sql_mode: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION time_zone: SYSTEM Create Event: CREATE EVENT `test_user_dr` и весь текст планировщика... character_set_client: cp1251 collation_connection: cp1251_general_ci Database Collation: cp1251_general_ci 1 row in set (0.00 sec)
Ну вроде все. Если есть вопросы пишите, буду отвечать.
Ссылки
Статья просмотренна 82285 раз, зашло посетителей 28761
Обалдеть! Ни разу об этом не слышал.
Все, прощай cron 🙂
Да это довольно интересно, единственно, что не удобное, если произошла какая-то ошибка, то крон мыло прислать может, написать в лог что-то, а тут увы никак…
А вообще некоторые действия которые я раньше делать через РНР и крон, теперь делаю напрямую.
Обрати внимание, что при создании дампа необходимо будет юзать специальные ключи , об этом я писал на странице http://blog.nagaychenko.com/2009/12/12/dump-mysql-создание-резервной-копии-бд/
Добрый день, Максим!
Не могли бы Вы помочь в составлении задания для планировщика следующего содержания (к сожалению, сам в SQL совершенно не силен).
Есть база base1 и в ней таблица table1, которая по каким то непонятным причинам время от времени рассыпается.
Нужно сделать задание для SQL планировщика, который бы каждые полчаса проверял "живая" ли таблица, и если она расспылась, вызывал на нее repair
Заранее спасибо!
Ну тут наверное важнее понять причину рассыпания. Конечно можно и задание написать, там всего-то несколько строку будет, но лучше получить от вас дамп БД. Если вы умеете пользоваться phpmyadmin, там есть такая вкладка как экспорт. Было бы лучше чтобы вы мне прислали этот дамп, на мыло maxnag[собака]meta.ua
Еще одна статья на данную тему http://plutov.by/post/mysql_event
А как это запустить с php?
пробовал так, но так почему-то не работает.
$sql = "CREATE EVENT myevent
ON SCHEDULE
AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
ON COMPLETION PRESERVE
DO DELETE FROM node";
mysql_query($sql);
РЕально а как его запустить то???
Привет! В статье написано, что на до сделать, чтобы его включить