在mysql的实际业务场景中,按日期范围筛选数据、按日期统计数据的需求十分普遍,比如查询某段时间内的订单记录、统计月度用户活跃量等。如果日期查询的写法不合理,很容易出现全表扫描的情况,导致查询耗时过长,影响业务响应速度。

日期查询性能差的常见原因
大部分日期查询性能问题都和索引使用不当有关,常见的问题有以下几类:
- 日期字段上没有建立对应的索引,查询时只能全表扫描匹配日期条件
- 在查询条件中对日期字段使用了函数或者运算,导致索引失效
- 查询的日期范围过大,即使有索引也需要扫描大量数据
- 日期字段的类型选择不合理,比如用字符串存储日期,比较时无法利用索引
mysql日期查询优化方法
1. 为日期字段建立合适的索引
如果业务中经常按某个日期字段查询,首先应该为该字段建立索引。如果查询经常同时包含日期和其他条件,可以建立联合索引,把日期字段放在合适的位置。
比如订单表经常需要按创建时间查询,同时可能按用户ID筛选,可以建立联合索引:
-- 为订单表的用户ID和创建时间建立联合索引 CREATE INDEX idx_user_create_time ON order_table (user_id, create_time);
2. 避免对日期字段使用函数或运算
在查询条件中对日期字段使用函数,比如DATE()、YEAR()等,会导致mysql无法使用索引,只能全表扫描。比如下面这种写法是不推荐的:
-- 不推荐的写法,对create_time使用DATE函数,索引失效 SELECT * FROM order_table WHERE DATE(create_time) = '2024-05-01';
可以改成范围查询的写法,既能利用索引,逻辑也和上面一致:
-- 推荐的写法,使用范围条件,可命中索引 SELECT * FROM order_table WHERE create_time >= '2024-05-01 00:00:00' AND create_time < '2024-05-02 00:00:00';
3. 选择合适的日期字段类型
存储日期时优先使用DATE、DATETIME、TIMESTAMP类型,不要使用字符串类型存储日期。字符串类型的日期比较需要逐字符匹配,无法利用日期类型的存储特性,也不容易命中索引。
如果只需要存储日期不需要时间,用DATE类型即可,占用空间更小,比较效率更高。
4. 合理控制查询的日期范围
如果业务允许,尽量缩小日期查询的范围,避免查询过长时间跨度的数据。比如统计月度数据时,明确指定月份的开始和结束时间,不要写成查询最近一年再在业务层过滤的方式。
5. 利用执行计划分析查询
写完查询语句后,可以用EXPLAIN关键字查看执行计划,判断索引是否被使用,扫描的行数是否合理。
-- 查看查询的执行计划 EXPLAIN SELECT * FROM order_table WHERE user_id = 1001 AND create_time >= '2024-05-01 00:00:00' AND create_time < '2024-05-31 23:59:59';
执行计划中的type字段如果是range、ref等表示使用了索引,如果是ALL则表示全表扫描,需要优化查询条件或者索引。
注意事项
如果日期字段允许为NULL,需要注意NULL值对索引的影响,查询时如果条件包含IS NULL或者IS NOT NULL,也要确认索引是否支持这类条件的查询。
另外,联合索引的顺序很重要,查询条件中日期字段前面的字段如果过滤性更好,联合索引的效率会更高,需要根据实际业务的查询频率调整索引字段的顺序。