MySQL事件调度器未启用会导致CREATE EVENT静默失败或报错ERROR 1477;需先用SHOW VARIABLES LIKE 'event_scheduler'检查,若为OFF则SET GLOBAL event_scheduler = ON临时开启,或在my.cnf中配置event_scheduler=ON并重启以永久启用。

MySQL事件调度器没启用,CREATE EVENT会直接报错
执行 CREATE EVENT 前必须确认事件调度器已开启,否则语句静默失败或报错 ERROR 1477 (HY000): The event scheduler is disabled。不是所有 MySQL 实例默认打开它。
检查方式:SHOW VARIABLES LIKE 'event_scheduler'; —— 返回 OFF 就得手动开。
- 临时启用(重启失效):
SET GLOBAL event_scheduler = ON; - 永久启用:在
my.cnf或my.ini的[mysqld]段落里加一行event_scheduler = ON,然后重启 MySQL - 注意权限:执行
SET GLOBAL需要SUPER权限(MySQL 8.0+ 改为SYSTEM_VARIABLES_ADMIN+ROLE_ADMIN)
日志表时间字段类型不匹配,DATE_SUB(NOW(), INTERVAL 30 DAY) 可能查不到数据
如果日志表的“创建时间”字段是 datetime 类型,用 DATE_SUB(NOW(), INTERVAL 30 DAY) 没问题;但如果是 timestamp 且带时区转换,或字段存的是字符串(如 VARCHAR 存 '2024-05-01 10:20:30'),WHERE created_at 很可能漏删或全删错。
- 先确认字段真实类型:
DESCRIBE log_table;或SHOW COLUMNS FROM log_table LIKE 'created_at'; - 若为字符串,必须先转成时间再比较,例如:
STR_TO_DATE(created_at, '%Y-%m-%d %H:%i:%s') (格式需严格匹配) - 若字段是
timestamp且服务器时区和写入时区不一致,建议统一用CONVERT_TZ()校准,或改用UTC_TIMESTAMP()写入并比对
批量删除不加 LIMIT 或分批逻辑,容易锁表或拖垮线上服务
直接 DELETE FROM log_table WHERE created_at 删除几十万行,会持有表级/行级锁较长时间,阻塞写入、触发慢查询告警,甚至导致主从延迟飙升。
- 生产环境严禁无限制
DELETE,应主动分批,例如每次删 5000 行:DELETE FROM log_table WHERE created_at - 事件中不能直接用
LIMIT(MySQL 5.7+ 允许,但 5.6 不支持),所以推荐用存储过程封装分批逻辑,再由事件调用 - 示例片段(需先创建):
DROP PROCEDURE IF EXISTS purge_old_logs;<br>DELIMITER $$<br>CREATE PROCEDURE purge_old_logs()<br>BEGIN<br> DECLARE row_count INT DEFAULT 1;<br> WHILE row_count > 0 DO<br> DELETE FROM log_table <br> WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY) <br> ORDER BY id LIMIT 5000;<br> SET row_count = ROW_COUNT();<br> END WHILE;<br>END$$<br>DELIMITER ;
事件定义里没设 ON COMPLETION PRESERVE,删完一次就自动失效
MySQL 默认事件执行完就 DROP 自己,除非显式声明保留。如果只写 CREATE EVENT ... DO CALL purge_old_logs();,第一次跑完事件状态就变成 SLAVESIDE_DISABLED 或直接消失,后续不再触发。
- 务必加上:
ON COMPLETION PRESERVE ENABLE - 完整示例:
CREATE EVENT ev_purge_logs<br>ON SCHEDULE EVERY 1 DAY<br>STARTS TIMESTAMP(CURDATE() + INTERVAL 1 DAY)<br>DO CALL purge_old_logs();<br>ALTER EVENT ev_purge_logs ON COMPLETION PRESERVE ENABLE;
- 注意
STARTS时间别设成过去时刻,否则事件立即触发一次后可能卡住;用CURDATE() + INTERVAL 1 DAY更稳妥
真正麻烦的不是写事件,而是确认日志表的索引是否覆盖了 created_at 字段——没索引的话,每次扫描全表,分批也救不了性能。删之前先 EXPLAIN 一下那个 WHERE 条件。


















