mysql删除大量数据前需禁用触发器,因其会在每行delete时执行,导致性能严重下降;实际应通过rename trigger临时重命名绕过,而非drop或set sql_log_bin,删后须及时恢复并验证。

MySQL 删除大量数据前为什么要先禁用触发器
因为触发器会在每次 DELETE 操作时自动执行,如果表上有 AFTER DELETE 或 BEFORE DELETE 触发器,且涉及复杂逻辑(比如写日志、更新统计表、调用存储过程),每删一行都会触发一次——100 万行就触发 100 万次,极易导致锁表时间过长、事务膨胀、binlog 爆增,甚至主从延迟飙升或 OOM。
直接禁用比在触发器里加条件判断更可靠,也避免误判“哪些行该跳过触发”。
-
DROP TRIGGER不推荐:删了还得重建,容易遗漏或版本不一致 -
SET SQL_LOG_BIN = 0仅禁用 binlog,不影响触发器执行 - 真正有效的是
DISABLE TRIGGER—— 但注意:MySQL 原生不支持该语法(这是 SQL Server 的)
MySQL 实际可用的触发器禁用方案
MySQL 没有 DISABLE TRIGGER,必须用变通方式绕过。最稳妥的是临时重命名触发器,再删完恢复:
RENAME TRIGGER `tbl_after_delete_log` TO `tbl_after_delete_log_disabled`;
重命名后原名失效,触发逻辑不会执行;删除完成后用同样语句改回来即可。注意:
- 触发器名必须带数据库名前缀,如
mydb.tbl_after_delete_log,否则可能报错ERROR 1357 (HY000): Cannot rename a trigger created in another database - 不能用
ALTER TRIGGER修改状态,MySQL 不支持 - 如果触发器依赖其他对象(如函数、表),重命名不影响其定义,只是让 MySQL 在 DELETE 时不匹配到它
分批物理删除的核心控制点
不分批直接 DELETE FROM t WHERE ... 容易锁全表、占满 undo log、堵塞后续 DML。必须用主键/唯一索引 + LIMIT 控制节奏:
DELETE FROM t WHERE id BETWEEN 100000 AND 199999 LIMIT 1000;
关键实操建议:
- 优先用
WHERE id > ? ORDER BY id LIMIT N,避免BETWEEN在高并发下漏删或重复删 - 每次删除后加
SLEEP(0.1)(在存储过程中用DO SLEEP(0.1)),缓解 I/O 和锁竞争 - 监控
SHOW ENGINE INNODB STATUS中的TRX_ROWS_LOCKED,若持续 > 10w 行,说明单批太大 - 避免在从库执行,防止复制中断;如必须,先
STOP SLAVE,删完再START SLAVE
删完后务必验证和清理
很多人删完就跑,结果发现触发器没恢复、自增 ID 异常、或 binlog 位点错乱:
- 用
SHOW TRIGGERS LIKE 't'确认触发器名已还原,且Timing和Event字段与之前一致 - 检查
SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES,大批量删除不会重置自增,但某些 ORM 会误判,需手动ALTER TABLE t AUTO_INCREMENT = ? - 如果用了
SET SQL_LOG_BIN = 0,记得切回SET SQL_LOG_BIN = 1,否则后续操作不写 binlog - 最后跑一次
ANALYZE TABLE t,更新统计信息,避免优化器选错执行计划
重命名触发器这步最容易被跳过,一删了之,结果第二天业务日志全丢——得盯着它改回来。











