本文对比了三种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'
结论
日期范围比较方式最优,理由:
-
性能最好(可使用索引)
-
代码最简洁
-
边界处理最准确
-
类型最安全
除非表设计上已经将月份作为独立字段存储,否则应优先使用日期范围比较。