WHERE条件中避免对日期字段使用DATE()、YEAR()等函数,否则MySQL会放弃索引导致全表扫描;应改用范围查询(如create_time >= '2026-01-01' AND create_time < '2027-01-01')并建立以等值字段为首的复合索引。

WHERE条件里别对日期字段用DATE()、YEAR()这些函数
只要在WHERE里对索引字段套函数,MySQL基本就放弃走索引了。比如DATE(order_time) = '2026-07-01'看着直观,但实际会全表扫描——哪怕order_time上早有索引。
原因很简单:函数改变了字段原始值的可比较性,优化器无法直接用B+树索引做范围定位。
- 错误写法:
WHERE YEAR(create_time) = 2026、WHERE DATE_FORMAT(create_time, '%Y-%m') = '2026-07' - 正确替代:
WHERE create_time >= '2026-01-01' AND create_time (查全年) - 查当月更稳妥:
WHERE create_time >= '2026-07-01' AND create_time ,比<code>DATE_FORMAT或MONTH()安全得多
用>=和
BETWEEN '2026-07-01' AND '2026-07-31'表面看是查整月,但隐式补零后变成'2026-07-01 00:00:00'到'2026-07-31 00:00:00',漏掉31号全天大部分数据;而BETWEEN '2026-07-01 00:00:00' AND '2026-07-31 23:59:59'又可能因毫秒精度丢失最后几条记录。
半开区间(左闭右开)天然规避边界歧义:
- 查当天:
WHERE create_time >= '2026-07-02' AND create_time - 查本周:
WHERE create_time >= '2026-06-29' AND create_time (周一为起点) - 查最近7天:
WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND create_time
复合索引顺序要按筛选强度排
如果查询总带用户ID和时间范围,比如WHERE user_id = 123 AND create_time >= '2026-07-01',只给create_time建单列索引效果有限。
此时应建复合索引,且把等值条件字段放前面:
- 推荐:
ALTER TABLE orders ADD INDEX idx_user_time (user_id, create_time) - 不推荐:
idx_time_user (create_time, user_id)——因为范围查询字段放后面,索引只能用到前半部分 - 注意:
user_id区分度越高(如唯一ID),越适合作为复合索引首列
超大表考虑按日期分区,但别过早引入
RANGE分区对亿级订单表确实有用,比如按create_time每月一分区,查某月数据只需扫一个分区。但分区不是银弹:
- 分区键必须是索引的一部分,否则无法生效
- 维护成本高:需定期
ALTER TABLE ... REORGANIZE PARTITION新增分区 - 小表(
- 先确认
EXPLAIN显示已走索引且仍慢,再考虑分区
真正容易被忽略的是:哪怕建了索引,如果查询里混用了OR、LIKE '%xxx'或隐式类型转换(比如create_time = '2026-07-02'但字段是DATETIME),索引照样失效。每次改完SQL,务必用EXPLAIN看一眼key和rows字段。


















