直接用current_date更稳妥,因now()含时分秒易与date类型字段隐式转换导致边界模糊;mysql应统一按日期粒度对齐,postgresql需用current_date - interval '6 days';null值、字符串存时间、低区分度字段均影响查询准确性。

WHERE条件里用DATE_SUB()还是CURRENT_DATE?
直接用 CURRENT_DATE 更稳妥。很多新手写成 date > DATE_SUB(NOW(), INTERVAL 7 DAY),结果发现查出来数据偏多——因为 NOW() 包含时分秒,而业务表里的 date 字段通常是 DATE 类型或只存日期部分,比较时会隐式转换,导致边界模糊。
正确写法是统一按日期粒度对齐:
- 如果字段是
DATE类型:用date >= DATE_SUB(CURRENT_DATE, INTERVAL 6 DAY)(注意是6天,不是7天——今天算第1天,往前推6天刚好覆盖最近7个自然日) - 如果字段是
DATETIME类型且需包含今天0点起的数据:用datetime >= DATE_SUB(CURRENT_DATE, INTERVAL 6 DAY),MySQL会自动补00:00:00 - 避免用
BETWEEN,它容易因时区或时间截断引发边界争议
PostgreSQL怎么写等效语句?
PostgreSQL不认 DATE_SUB,得换语法。核心是别硬套MySQL写法,否则报错 function date_sub(unknown, unknown) does not exist。
等效写法是:
-
created_at >= CURRENT_DATE - INTERVAL '6 days'(推荐,清晰且支持索引) - 别写
CURRENT_DATE - 6——虽然能运行,但语义不明确,且在某些版本可能触发隐式类型转换 - 如果字段带时区(如
TIMESTAMP WITH TIME ZONE),确保CURRENT_DATE和字段时区一致,否则可能漏掉跨时区的记录
为什么查出来的行数比预期少?
大概率是字段值为 NULL 或时间字段被错误地存成了字符串(比如 '2024-05-10' 存在 VARCHAR 字段里)。这类数据在 WHERE 条件中直接被过滤掉,连警告都没有。
快速排查方法:
- 先执行
SELECT COUNT(*) FROM table WHERE date_column IS NULL,确认空值比例 - 再跑
SELECT DISTINCT pg_typeof(date_column) FROM table LIMIT 1(PostgreSQL)或SHOW COLUMNS LIKE 'date_column'(MySQL),看实际类型是不是预期的DATE/DATETIME - 如果真是字符串类型,临时补救可用
STR_TO_DATE(date_str, '%Y-%m-%d')(MySQL)或date_column::DATE(PostgreSQL),但性能差,别长期这么用
加索引前先确认字段选择性
加了索引也不一定快。如果 date 字段重复值极高(比如全表90%数据都集中在最近7天),优化器很可能放弃走索引,改用全表扫描。
判断是否值得建索引:
- 执行
SELECT COUNT(DISTINCT date_column) / COUNT(*) FROM table,结果低于0.05说明区分度太低 - 用
EXPLAIN看执行计划里type是不是range或ref,如果是ALL就没走索引 - 复合查询(比如还要按
status过滤)时,优先建联合索引,如(date_column, status),顺序不能反
时间范围查询看着简单,但字段类型、NULL值、索引有效性这三点漏掉任何一个,结果就不可靠。











