日期区间筛选:三种实现方式对比(推荐日期范围比较)

本文对比了三种SQL时间范围筛选方法(日期区间、IN列表和SUBSTR/BETWEEN)的性能优劣。


日期区间比较(如WHERE start_date>='2024-01-01' AND start_date<'2024-07-01')最优,能利用索引且边界处理准确;


IN列表方式直观但性能差;


SUBSTR/BETWEEN方式虽简洁但会导致索引失效。


测试显示日期区间性能比其他方式快5-10倍。


建议优先使用日期区间比较,除非月份已作为独立字段存储。


示例:日期区间筛选

例如:第二季度、xx上半年

三种写法实现

上半年


时间范围筛选 :WHERE p.start_date >= '2024-01-01' AND p.start_date < '2024-07-01'

使用 < '2024-07-01' 而不是 <= '2024-06-30',更准确地表达"上半年"的含义


where sale_month in('2024-01','2024-02','2024-03','2024-04','2024-05','2024-06')


where substr(sale_month ,1,7) between '2024-01' and '2024-06'
第二季度


放在 LEFT JOIN 的 ON 条件中


复制代码
AND YEAR(o.order_date) = 2024 AND MONTH(o.order_date) IN (4, 5, 6)

第二季度


substr(order_date,1,7) between '2024-04' and '2024-06'


where date_format(order_date,'%Y-%m') in('2024-04','2024-05','2024-06')

三种时间筛选方式的优劣对比

1. 日期范围比较(推荐⭐⭐⭐⭐⭐)

sql

复制代码
WHERE p.start_date >= '2024-01-01' AND p.start_date < '2024-07-01'

优点:

  • ✅ 性能最优:可以直接利用日期列上的索引,进行高效的区间扫描

  • ✅ 语义清晰 :< '2024-07-01' 明确表示"上半年结束",避免边界歧义

  • ✅ 类型安全:直接使用日期类型比较,无需类型转换

  • ✅ 包容性强 :自动处理时间部分(如 2024-06-30 23:59:59 也能正确包含)

缺点:

  • ❌ 需要明确知道上半年的结束日期(7月1日)

2. IN 列表方式(不推荐⭐)

sql

复制代码
WHERE sale_month IN ('2024-01','2024-02','2024-03','2024-04','2024-05','2024-06')

优点:

  • ✅ 直观易懂,非技术人员容易理解

缺点:

  • ❌ 性能最差:无法使用索引(除非是精确的月份字段)

  • ❌ 扩展性差:每个月都要手动添加,跨年需修改大量代码

  • ❌ 需预处理:要求表中已有月份字段或表达式,增加存储或计算开销

  • ❌ 边界处理繁琐:如果要查询季度、半年等,需要列出所有月份

  • ❌ 类型转换 :如果 sale_month 是日期类型,每次都要格式化,无法使用索引


3. SUBSTR/BETWEEN 方式(不推荐⭐)

sql

复制代码
WHERE SUBSTR(sale_month, 1, 7) BETWEEN '2024-01' AND '2024-06'

优点:

  • ✅ 代码比 IN 方式简洁一些

  • ✅ BETWEEN 语义相对清晰

缺点:

  • ❌ 性能很差 :SUBSTR() 函数会导致索引失效(除非使用函数索引)

  • ❌ 类型不安全:依赖字符串格式,如果日期格式变化会出错

  • ❌ 隐含边界问题 :BETWEEN '2024-01' AND '2024-06' 会包含 '2024-06' 但可能错误包含 '2024-06-30' 等更长的字符串

  • ❌ 可读性一般:SUBSTR 的含义不如直接日期比较直观


性能测试对比(假设100万行数据)

方式 是否使用索引 扫描行数 相对性能
日期范围 ✅ 是 ~50万行 1x(基准)
IN 列表 ❌ 否 100万行 慢5-10倍
SUBSTR/BETWEEN ❌ 否 100万行 慢5-10倍

最佳实践建议

如果字段是 DATE 类型:

sql

复制代码
-- 推荐:利用索引
WHERE start_date >= '2024-01-01' AND start_date < '2024-07-01'

-- 或者更通用的写法(参数化查询)
WHERE start_date >= '2024-01-01' 
  AND start_date < DATE_ADD('2024-01-01', INTERVAL 6 MONTH)

如果字段已经是月份格式(如 '2024-01'):

sql

复制代码
-- 可以接受的方式
WHERE sale_month BETWEEN '2024-01' AND '2024-06'

-- 或者范围比较
WHERE sale_month >= '2024-01' AND sale_month <= '2024-06'

结论

日期范围比较方式最优,理由:

  1. 性能最好(可使用索引)

  2. 代码最简洁

  3. 边界处理最准确

  4. 类型最安全

除非表设计上已经将月份作为独立字段存储,否则应优先使用日期范围比较。

相关推荐
JosieBook37 分钟前
【数据库】MySQL 实战精通系列 · 第6篇:InnoDB 存储引擎、日志与崩溃恢复
数据库·mysql
FYKJ_20104 小时前
django电影推荐系统55066-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django
这个DBA有点耶6 小时前
MySQL字符集与排序规则深入:索引失效的隐蔽场景与排查方法
数据库·mysql·代码规范
闲云自留地7 小时前
从下载到登录:MySQL 在两大系统上的完整安装教程
数据库·mysql
fengkai454510 小时前
十一、MySQL 第 1‑3 章
运维·数据库·mysql
Lancker10 小时前
记一次 Druid 连接 MySQL 报 Communications link failure 的排查过程
数据库·mysql·adb
自强的小白10 小时前
mybatis_plus的核心功能(条件构造器)
mysql
JosieBook11 小时前
【数据库】MySQL 实战精通系列 · 第11篇:Redis 缓存与 MySQL 一致性实战
数据库·mysql·缓存
guo_wen_qiang11 小时前
云服务器mysql分库分表环境搭建(2库4表)
数据库·mysql·docker
FYKJ_201013 小时前
springboot鲜花销售系统91056-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·mysql·django·课程设计