mysql事件调度器默认关闭,需执行set global event_scheduler=on或配置my.cnf永久启用;创建事件需event权限;on schedule用every指定周期,单位用单数;delete须带where和limit防锁表;created_at需建索引;失败日志在error.log中。

MySQL 用 EVENT 实现定时清理,但默认关闭
MySQL 支持原生事件调度器(EVENT),但它不是默认启用的。直接建事件会报错 ERROR 1541: Event scheduler is not running。必须先确认并开启调度器,否则所有后续操作都无效。
- 运行
SHOW VARIABLES LIKE 'event_scheduler';查看当前状态,返回OFF就得手动开 - 临时开启:执行
SET GLOBAL event_scheduler = ON;(重启后失效) - 永久生效:在
my.cnf或my.ini的[mysqld]段下加一行event_scheduler = ON - 注意权限:创建事件需要
EVENT权限,不是所有账号都有,比如普通应用账号通常没有
CREATE EVENT 语法里 ON SCHEDULE 是关键,别写错时间单位
ON SCHEDULE 决定什么时候触发,常见错误是混淆 EVERY 的单位或误用 AT 做周期任务。
- 清理过期数据基本都用周期性执行:
EVERY 1 DAY、EVERY 1 HOUR,注意单位必须是单数(DAY不是DAYS) - 如果想从现在起 1 小时后首次运行,再每小时一次:用
EVERY 1 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR -
AT只执行一次,比如AT '2025-04-01 02:00:00',不适合清理类长期任务 - 时间表达式中不能用函数如
NOW(),只能用CURRENT_TIMESTAMP或字面量;否则建事件会报错ERROR 1064
事件体里 DELETE 要带 WHERE,且建议加 LIMIT 防锁表
事件主体是 SQL 语句,最常见就是 DELETE FROM table WHERE created_at 。但直接这么写有风险:
- 没
WHERE条件?删全表,别试 - 条件字段没索引?
created_at必须建索引,否则每次扫描全表,IO 和锁压力大 - 一次删太多行?InnoDB 下可能长时间持有行锁甚至升级为表锁,影响线上写入;加
LIMIT 1000并配合循环逻辑(需用存储过程)或分批调度 - 示例安全写法:
DELETE FROM logs WHERE created_at
- 如果表很大,更稳妥的做法是用
pt-archiver工具替代,它自带分批、限速、事务控制
事件状态和调试靠 SHOW EVENTS 和 ERROR LOG,别只看是否“存在”
建完事件不代表它真在跑。很多问题出在“看似创建成功,实则没触发”。
- 查看所有事件状态:
SHOW EVENTS\G,重点看Status列(ENABLED/DISABLED)、Last_executed(上次执行时间)、Originator(如果是主从,0 表示只在主库执行) - 事件失败不会抛到客户端,错误记录在 MySQL 错误日志(
error.log)里,搜关键词Event或具体事件名 - 测试阶段可手动触发:
ALTER EVENT clean_logs ENABLE;然后等下一周期,或临时改成EVERY 10 SECOND快速验证 - 事件默认在
definer用户上下文执行,如果该用户权限不足(比如没DELETE权),事件会静默失败
事件本身不难写,难的是让它稳定、可观测、不影响业务。尤其是 event_scheduler 的开关状态、DEFINER 权限、以及没索引的 WHERE 条件,这三个点最容易漏查。










