
查最近N天的数据,关键不在写SQL本身,而在准确理解业务时间字段含义、时区影响和索引有效性。直接用 WHERE create_time >= DATE_SUB(NOW(), INTERVAL N DAY) 很常见,但容易踩坑。
明确时间字段类型和存储逻辑
MySQL中常见时间字段有 DATETIME、TIMESTAMP 和 INT(时间戳秒数)。不同字段对函数处理和索引支持差异大:
-
DATETIME:不带时区,建议用DATE_SUB(NOW(), INTERVAL N DAY),且确保该字段有索引 -
TIMESTAMP:自动转为UTC存储,查询时需注意连接会话时区(SET time_zone = '+08:00'),否则可能漏数据 -
INT存秒级时间戳:推荐用WHERE ts >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL N DAY)),避免在字段上用函数(如FROM_UNIXTIME(ts))导致索引失效
避免函数作用于索引列
写条件时,让计算发生在右边,别把函数套在左列上。以下写法会让 create_time 索引失效:
❌ 错误示例:WHERE DATE(create_time) >= '2024-06-01'
正确做法是推算出时间边界,直接比较原始值:
✅ 推荐写法:WHERE create_time >= '2024-06-01 00:00:00' AND create_time
或者用区间函数(MySQL 8.0+):WHERE create_time BETWEEN '2024-06-01' AND '2024-06-01 23:59:59',但注意 BETWEEN 是闭区间,精度要对齐。
考虑业务“最近N天”的真实定义
“最近N天”可能是:
-
自然日:从今天0点往前推N天(如今天6月5日,N=3 → 查6月2日00:00起的数据),用
DATE_SUB(CURDATE(), INTERVAL N DAY) -
滚动N×24小时:从当前时刻倒推N天(如现在是6月5日14:30,N=3 → 查6月2日14:30起的数据),用
DATE_SUB(NOW(), INTERVAL N DAY) -
按业务日切分:某些系统以早6点或晚8点为日切分点,需手动调整基准时间,例如:
DATE_SUB(DATE_ADD(NOW(), INTERVAL 6 HOUR), INTERVAL N+1 DAY) + INTERVAL 6 HOUR(适配早6点日切)
加索引与执行计划验证
即使条件写对,没索引也慢。确认执行计划是否走索引:
EXPLAIN SELECT * FROM orders WHERE create_time >= DATE_SUB(NOW(), INTERVAL 7 DAY);
重点看 type 是否为 range 或更好,key 是否显示用了索引名。若显示 type=ALL,说明全表扫描——检查是否索引缺失、字段类型不匹配,或WHERE中对列用了函数。









