WHERE条件应使用与created_at字段存储时区一致的时间;若created_at存UTC时间(推荐),则WHERE条件需用UTC时间。

WHERE条件必须用UTC时间还是本地时间?
取决于你的日志表created_at字段存储的是哪种时区的时间。如果应用写入时统一用UTC(推荐),那WHERE created_at 会出错——因为<code>NOW()返回的是数据库服务器本地时间。更安全的做法是用UTC_TIMESTAMP():
DELETE FROM log_table WHERE created_at < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 90 DAY);如果字段存的是本地时间(比如东八区),且服务器时区设为
+08:00,那用NOW()才匹配。
DELETE大表卡住或锁表怎么办?
直接DELETE FROM log_table WHERE created_at 在百万级以上数据上容易长时间持有行锁甚至锁表,导致业务写入阻塞。应该分批删除:<br><pre class="brush:php;toolbar:false;">DELETE FROM log_table WHERE created_at < '2024-03-01' LIMIT 10000;</pre>然后循环执行,每次删完检查影响行数是否为0。关键点:<br><ul>
<li>务必在<code>created_at字段上有索引,否则LIMIT无效(MySQL仍需全表扫描)
SLEEP(0.1)(应用层控制),避免IO打满ORDER BY配合LIMIT——MySQL 5.7+对带WHERE + ORDER BY + LIMIT的DELETE不走索引优化误删后能回滚吗?
仅当满足以下全部条件时才能靠事务回滚:
- 使用的是
InnoDB引擎(MyISAM不支持事务) - 删除操作没显式
COMMIT,且连接未断开 - 没开启
autocommit=1(默认开启,所以绝大多数情况删完就不可逆)
CREATE TABLE log_table_bak_202406 AS SELECT * FROM log_table WHERE created_at < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 90 DAY);或者用
mysqldump导出待删数据段,而不是依赖回滚。有没有比DELETE更省资源的方案?
有,但只适用于按时间分区的表。如果日志表已按月/周建了PARTITION,直接DROP PARTITION几乎瞬时完成,不走逐行删除逻辑:
ALTER TABLE log_table DROP PARTITION p202401, p202402, p202403;前提是建表时用了
PARTITION BY RANGE (TO_DAYS(created_at))这类策略。没分区的话,别试图用TRUNCATE——它不能带WHERE,会清空整表。
真正麻烦的不是语法,而是删之前没人确认过哪些下游任务还依赖这些旧日志——比如审计系统拉取三个月前的原始记录,一删就报空指针。时区、索引、事务、分区,每个点漏掉一个,清理就会变成事故前奏。

















