为何含200万行数据的MySQL查询耗时超5秒?已建created_at索引
问题分析与解答
这个查询耗时超5秒不符合预期,核心问题出在查询语句对索引字段的不合理使用上,具体分析和优化方案如下:
问题根源
你虽然给created_at字段建了索引,但WHERE子句中用DATE(created_at)函数包裹了该字段,这会导致MySQL无法直接利用created_at的索引做高效的范围查询,只能执行全表扫描(从EXPLAIN结果能看到扫描行数接近全表200万)。全表扫描加上后续的分组统计,自然会导致耗时过长。
优化方案
1. 改写WHERE条件,避免函数包裹索引字段
把原WHERE条件:
DATE(created_at) BETWEEN '2022-09-09' AND '2022-09-12'
改为:
created_at BETWEEN '2022-09-09 00:00:00' AND '2022-09-12 23:59:59'
这样MySQL可以直接使用created_at的索引进行范围过滤,只扫描符合日期范围的行,而非全表。
2. 优化索引(可选)
如果想进一步提升性能,可以创建覆盖索引:
CREATE INDEX idx_created_at ON advert_requests(created_at);
(如果已有该索引则无需重复创建)。InnoDB的二级索引叶子节点会包含主键信息,这个索引可以让查询直接从索引中获取created_at数据,无需回表查询原数据,进一步减少IO开销。
3. 分组语句简化(不影响性能,仅写法优化)
分组时可以直接使用函数表达式,无需依赖别名,写法更简洁:
GROUP BY DATE(created_at), HOUR(created_at)
效果验证
修改后重新执行EXPLAIN,你会看到type变为range,rows字段显示的是符合日期范围的行数(远小于200万),此时查询耗时会大幅降低,通常能控制在几百毫秒内。
内容的提问来源于stack exchange,提问作者James Mills
相关产品推荐
相关产品推荐

