用 curdate() - interval 7 day 构造起始时间可准确查最近7天活跃用户,因 curdate() 返回 date 类型,减整数会触发危险隐式转换;必须用 interval 保证类型安全、语义清晰,并确保 last_login 字段有有效索引。

MySQL中用CURDATE()和INTERVAL查最近7天活跃用户
直接上结论:用 CURDATE() - INTERVAL 7 DAY 构造起始时间,配合 WHERE login_time >= ... 就能准确筛选——但要注意时区、字段类型和索引是否生效。
为什么不能写成 CURDATE() - 7?
CURDATE() 返回的是 DATE 类型(如 '2024-06-15'),减整数在 MySQL 中会触发隐式转换,变成“从该日期对应的数值(如 20240615)减去7”,结果完全不可控。真实场景下常误查出 20240608 这类数字,而非日期。
正确做法必须显式使用 INTERVAL:
SELECT user_id FROM users WHERE last_login >= CURDATE() - INTERVAL 7 DAY;
-
CURDATE() - INTERVAL 7 DAY是标准语法,类型安全,语义清晰 - 如果字段是
DATETIME或TIMESTAMP,也适用;MySQL 会自动对齐精度(即'2024-06-15'等价于'2024-06-15 00:00:00') - 若需包含今天 23:59:59 的数据,建议改用
>= DATE_SUB(CURDATE(), INTERVAL 7 DAY)并确保字段有索引
last_login 字段没索引?查询可能全表扫描
即使 SQL 写对了,last_login 字段若没建索引,哪怕只查 7 天,也可能扫完整个用户表——尤其当表超百万行时,响应从毫秒级掉到秒级。
检查并补索引:
SHOW INDEX FROM users WHERE Column_name = 'last_login';
- 没有输出?立刻加:
ALTER TABLE users ADD INDEX idx_last_login (last_login); - 已有索引但类型是
TEXT或函数包装(如DATE(last_login)),索引无效,得重写查询或建函数索引(MySQL 8.0+) - 复合查询带
user_status = 'active'?考虑联合索引:(last_login, user_status),顺序很重要
跨日界线的“最近7天”到底从哪算起?
CURDATE() - INTERVAL 7 DAY 是按日历日截断计算的,比如今天是 2024-06-15,它返回 2024-06-08,范围是 2024-06-08 00:00:00 到 2024-06-15 23:59:59(取决于你 WHERE 条件是否含 )。
- 如果业务要求“过去168小时”,请改用
NOW() - INTERVAL 168 HOUR,避免日历日跳变影响(例如闰秒、夏令时) - 如果数据库时区不是系统时区(
SELECT @@time_zone;),CURDATE()结果可能和应用端理解不一致,务必统一配置 - 导出报表或定时任务中硬编码
CURDATE()要小心:凌晨跑批时,CURDATE()已更新,可能漏掉前一日 23:xx 的活跃记录
实际用的时候,最常被忽略的是索引缺失和时区错位——写对了 SQL,查不出数据,十次有八次是这两个原因。










