between更简洁且语义清晰,但需注意边界包含性;>=和

WHERE子句中用BETWEEN还是>=和
直接用 BETWEEN 看似简洁,但对日期类型容易漏数据——它会自动包含边界时间的 00:00:00 和 23:59:59,而你的字段如果是 DATETIME 或 TIMESTAMP,末尾可能有毫秒或微秒(比如 '2024-05-01 14:23:45.123'),BETWEEN '2024-05-01' AND '2024-05-31' 实际等价于 BETWEEN '2024-05-01 00:00:00' AND '2024-05-31 00:00:00',直接砍掉整日。
更稳妥的做法是用左闭右开区间:
-
created_at >= '2024-05-01'(隐式转为'2024-05-01 00:00:00') created_at (避开手算 23:59:59,也兼容毫秒)
这样既能覆盖整个5月,又不依赖字段精度,还能命中索引。
日期字段类型不同,写法要跟着变
MySQL里常见三种时间字段:DATE、DATETIME、TIMESTAMP。它们对字符串字面量的隐式转换行为不一致:
-
DATE字段比较时,'2024-05-01'会被当纯日期处理,没问题 -
DATETIME/TIMESTAMP字段遇到'2024-05-01',MySQL 默认补成'2024-05-01 00:00:00',所以WHERE dt_col = '2024-05-01'其实只查当天零点那一行 - 如果想查某天全部记录,必须显式写范围,或者用
DATE(dt_col) = '2024-05-01'—— 但注意:这会让dt_col上的索引失效
结论:优先用范围查询,避免在日期字段上套函数。
时区问题让查询结果“凭空消失”
如果你的表用 TIMESTAMP 类型,而应用和MySQL服务器时区不一致(比如应用传的是东八区时间 '2024-05-01 10:00:00',MySQL server 配置的是 UTC),那直接拿这个字符串去查,实际存进库的是 UTC 时间 '2024-04-30 02:00:00',导致查不到。
解决办法只有两个:
- 统一所有环节时区:设置
time_zone='+08:00'(连接级或全局),再传入带时区感知的时间字符串(如'2024-05-01 10:00:00+08:00',需 MySQL 8.0.19+) - 或者,业务层把输入时间转成 UTC 再传入,查的时候也按 UTC 范围写(比如查东八区 5 月 1 日,实际查
UTC 时间 4 月 30 日 16:00:00到5 月 1 日 16:00:00)
用 DATETIME 可绕过这个问题,但它不自动转换时区,得靠应用自己管好“存什么、查什么”。
大表加 LIMIT 前先确认是否真需要排序
查日期范围内数据常搭配 ORDER BY created_at DESC LIMIT 20 做分页。但如果 created_at 没索引,或者复合索引顺序不对(比如你建了 (status, created_at) 却按 created_at 单独排序),MySQL 可能触发 filesort,几百万行就卡住。
检查执行计划:EXPLAIN SELECT ... WHERE created_at >= '2024-05-01' AND created_at
关键看 type 是否为 range,key 是否命中索引,Extra 有没有 Using filesort。没索引就加,有索引但没生效,可能是范围条件后还有其他过滤字段干扰了索引使用顺序。
真正容易被忽略的点:日期范围查询本身很快,但一旦带上非索引字段的 ORDER BY 或 GROUP BY,性能可能断崖下跌——别默认认为“查最近一周”就一定快。











