时间范围查询慢主因是时间字段未建索引或索引未被正确使用;需通过 EXPLAIN 确认索引是否生效,优先为时间字段建 B + 树单列索引,避免函数操作,复合索引须等值字段在前、范围字段在后,并结合分区或归档优化大表性能。

时间范围查询慢,大概率是时间字段没建索引,或索引没被正确使用。重点不是加了索引就万事大吉,而是索引类型、字段顺序、查询写法都要匹配。
确认时间字段是否已有有效索引
执行 EXPLAIN 查看实际执行计划:
- 如果 type=ALL 或 key=NULL,说明没走索引;
- 如果 key 显示用了索引但 rows 很大,可能是索引选择性差或范围过大;
- 注意 Extra 列:出现 Using filesort 或 Using temporary,往往意味着排序 / 分组没利用索引,可能需覆盖索引优化。
优先用单独时间字段的 B + 树索引
对纯时间范围(如 WHERE create_time BETWEEN '2024-01-01' AND '2024-06-30'),最直接有效的是在该时间字段上建普通索引:
CREATE INDEX idx_create_time ON orders(create_time);- 避免用函数包裹时间字段,例如
WHERE DATE(create_time) = '2024-01-01'会失效索引; - 时间字段类型尽量统一:用
DATETIME或TIMESTAMP,别混用字符串存时间。
复合索引要注意字段顺序和查询模式
如果查询常带其他条件(如状态 + 时间),可建复合索引,但顺序很关键:
- 等值条件字段放前面,范围条件字段放最后 —— 例如常用
WHERE status = 1 AND create_time > '2024-06-01',应建INDEX idx_status_time (status, create_time); - 反过来建
(create_time, status),status就无法走索引; - 若同时有
ORDER BY create_time DESC LIMIT 20,这个复合索引还能避免排序,一举两得。
分区表或归档旧数据,缓解大表压力
当单表超千万行且历史数据极少更新时,索引效率会下降:
- 考虑按月 / 年对时间字段做 RANGE 分区 (MySQL)或 时间分区表(PostgreSQL);
- 定期归档一年前数据到历史表,主表体积减小,索引更紧凑、更高效;
- 注意:分区不是银弹,需配合查询条件中的分区键(通常是时间字段)才能生效。
不复杂但容易忽略:索引建了要验证是否真被用上,范围查得越窄响应越快,旧数据及时归档比硬扛更可持续。