mysql定期清理需依赖event调度器或外部cron,event须先启用event_scheduler并用存储过程分批删除,云环境则推荐crontab调用;直接在event中执行delete风险极高。

MySQL 本身不提供“开箱即用”的定期清理机制,所谓“自动”,本质是定时执行 DELETE 语句——要么靠数据库内置的 EVENT 调度器,要么靠外部 cron 调用。选哪种,取决于你能不能控制 MySQL 配置、有没有 EVENT 权限、以及是否在云环境(如阿里云 RDS)上运行。
event_scheduler 没开,CREATE EVENT 必定失败
很多人写完 CREATE EVENT 就报错,比如 ERROR 1541: Event scheduler is not running 或看似无关的 ERROR 1547: Event execution time is in the past,根本原因就一个:调度器压根没启动。
- 先查状态:
SHOW VARIABLES LIKE 'event_scheduler';—— 返回OFF就得开 - 临时启用(重启失效):
SET GLOBAL event_scheduler = ON; - 永久生效:在
my.cnf的[mysqld]段加event_scheduler = ON,然后重启 MySQL - 云数据库(如阿里云 RDS、腾讯云 CDB)通常禁用该变量,
EVENT不可用,别白费劲
直接在 EVENT 里写 DELETE 是高危操作
CREATE EVENT ... DO DELETE FROM logs WHERE created_at 看似简洁,但大表上极易锁表、拖慢主从、甚至触发 <code>Lock wait timeout exceeded。
- 正确做法是
EVENT只负责唤起存储过程:DO CALL clean_old_logs(); - 存储过程里必须用
WHILE+DELETE ... LIMIT 10000分批删,每次删完加DO SLEEP(0.1) - 删前务必确认时间字段(如
created_at)有索引,否则LIMIT也挡不住全表扫描 - 别用
TRUNCATE TABLE:它不走事务、不能带条件、无法回滚,不是“清理过期数据”,是“一键归零”
云环境或权限受限时,crontab 调用 mysql -e 更可靠
当 event_scheduler 被禁用、账号没有 EVENT 权限、或主从复制下事件不自动同步时,外部调度反而更可控。
- Linux 上一行
cron就能搞定:0 2 * * * mysql -u admin -p'xxx' -e "CALL mydb.clean_old_logs();" - 密码别明文写进命令,改用
~/.my.cnf配置文件存放凭证 - 命令可加日志重定向:
>/var/log/clean_logs.log 2>&1,出错能查 - 脚本里可先
SELECT COUNT(*)预估待删量,避免空跑或误判
ON SCHEDULE 时间表达式写错,事件就静默失效
EVERY 1 DAY STARTS NOW() 看似合理,但 NOW() 在事件定义时刻就被求值了,后续每次触发都用同一个时间戳,实际不会“每天更新”。
- 安全写法是:
EVERY 1 DAY STARTS CURRENT_TIMESTAMP - 想延迟首次执行(比如建完等 1 小时再开始):
EVERY 1 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR -
AT只适合一次性任务,清理类长期任务别用 - 单位必须是单数:
EVERY 1 DAY✅,EVERY 1 DAYS❌
真正容易被忽略的是:无论用 EVENT 还是 cron,时间字段有没有索引、单次删多少行、要不要加 SLEEP、以及是否在业务低峰期执行——这些细节不处理好,清理任务本身就会变成新的故障源。











