日期范围、月底和时间边界
使用半开区间处理整天整月,避免遗漏小数秒并保留索引机会。
问题与判断方法
筛选整月数据时,不要把结束时间写成 23:59:59。字段可能包含毫秒或微秒,也可能受时区转换影响。更稳定的写法是 created_at >= 月初且 created_at < 下月月初。
在 WHERE 中对日期字段套 DATE_FORMAT、DATE 或 YEAR,可能让普通索引难以使用。范围条件直接作用于原字段,通常更清楚也更有利于优化器。
应用还应统一存储时区和展示时区。跨时区日报要先确定“某一天”按用户、业务还是 UTC 边界计算。
示例
示例数据表
表名:
orders| id | customer_id | product_id | name | department | amount | status | created_at | discount |
|---|---|---|---|---|---|---|---|---|
| 1 | 101 | 201 | Alice | Sales | 1200 | paid | 2026-01-03 | 0 |
| 2 | 102 | 202 | Bob | IT | 900 | pending | 2026-01-08 | 50 |
| 3 | 101 | 201 | Cindy | Sales | 1500 | paid | 2026-02-02 | 100 |
| 4 | 104 | 203 | David | HR | 700 | cancelled | 2026-02-15 | 0 |
优化前 / 不推荐
SELECT * FROM orders WHERE DATE_FORMAT(created_at, '%Y-%m') = '2026-02' ORDER BY created_at;优化前运行结果
| id | customer_id | product_id | name | department | amount | status | created_at | discount |
|---|---|---|---|---|---|---|---|---|
| 3 | 101 | 201 | Cindy | Sales | 1500 | paid | 2026-02-02 | 100 |
| 4 | 104 | 203 | David | HR | 700 | cancelled | 2026-02-15 | 0 |
优化后 / 推荐
SELECT * FROM orders WHERE created_at >= '2026-02-01' AND created_at < '2026-03-01' ORDER BY created_at;优化后运行结果
| id | customer_id | product_id | name | department | amount | status | created_at | discount |
|---|---|---|---|---|---|---|---|---|
| 3 | 101 | 201 | Cindy | Sales | 1500 | paid | 2026-02-02 | 100 |
| 4 | 104 | 203 | David | HR | 700 | cancelled | 2026-02-15 | 0 |
为什么这样更好:半开区间覆盖二月的全部时间精度,并让条件直接作用于 created_at。
这篇内容是否清楚?
感谢反馈,我们会把它用于后续内容复核。