核心思路是用where条件按时间字段筛选最近30天数据,需根据数据库类型选择对应日期函数,注意时区、索引和比较符(>=或>)的业务含义,并优先验证查询结果再执行delete。

WHERE条件直接过滤日期字段
核心思路是用 WHERE 筛出 created_at(或你的时间字段)大于等于“30天前”的记录。别先想着删数据,先确认查出来对不对:
- MySQL:用
DATE_SUB(NOW(), INTERVAL 30 DAY) - PostgreSQL:用
CURRENT_DATE - INTERVAL '30 days' - SQL Server:用
DATEADD(day, -30, GETDATE()) - SQLite:用
date('now', '-30 days')
示例(MySQL):
SELECT * FROM logs WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY);执行前务必检查
created_at 是 DATETIME 还是 TIMESTAMP,时区不一致会导致漏掉或误删。DELETE语句慎用,必须加WHERE且验证
真要清理旧数据,DELETE 必须带明确的 WHERE 条件,且不能省略时间字段的索引——否则全表扫描可能锁表几分钟甚至更久。
- 执行前先
EXPLAIN看是否走了索引(比如EXPLAIN DELETE FROM logs WHERE created_at ) - 大表建议分批删:
DELETE FROM logs WHERE created_at ,循环执行 - 千万别写成
DELETE FROM logs没WHERE—— 这不是保留,这是清空
考虑分区表或归档替代硬删除
如果每天新增量大、查询常按日期范围,硬删不是最优解。分区表(如 MySQL 的 PARTITION BY RANGE (TO_DAYS(created_at)))能直接 DROP PARTITION,毫秒级完成,且不影响其他数据。
- PostgreSQL 支持按日期范围分区,
DETACH分区后可单独处理 - 归档方案:把旧数据
INSERT INTO archive_logs SELECT ...再删,留个底 - 注意:分区字段必须是
INT或可转为整型的表达式(如TO_DAYS()),不能直接用DATETIME
WHERE里用>=还是>取决于你的业务边界
“最近30天”到底包不包括今天?是否包含零点?这直接影响 >= 还是 > 的选择。
- 若要包含今天全部数据:用
created_at >= '2024-05-01 00:00:00'(假设今天是6月1日) - 若只保留严格过去30×24小时:用
created_at > DATE_SUB(NOW(), INTERVAL 30 DAY) - 时区坑:数据库服务器时区 vs 应用层时区,
NOW()返回的是服务器本地时间,不是 UTC
最稳妥的做法是用具体时间字符串代替函数,比如 '2024-05-01 00:00:00',避免执行时刻偏差。











