需求:
有这样一张表(数据有5KW左右),我需要按照时间过滤出一部分数据,然后将这部分数据分页获取;
id 主键
create_date 时间戳 (二级索引)
还有其他几十个字段
问题描述:
我写的SQL大致如下:
SELECT 很多个字段 FROM 表 WHERE create_date <= '2019-05-06' AND create_date >= '2019-05-05' ORDER BY id LIMIT C, S;
create_date 时间过滤,出来的数据大概有40W左右;
Explain 看了一下,会扫描的数据大概在80W左右,还算比较合理;也会走到索引(个人第一直觉就是能用到的两个字段都有索引,不会有撒问题);就上线了;
上线后发现这个语句要执行上千S,顿时就头大了;
问题原因:
只有将SQL再explain一下,看看语句执行的解析过程;发现跟之前看的没撒差别,但是这次我发现最后EXTRA 信息中有个 filesort;之前应该也有,我忽略了;
大致找到问题所在了,使用了内存或磁盘排序,导致数据处理缓慢;
但是这个和我潜意识的想法有点差别,两个列都有索引,为什么会出来filesort呢;
再一看语句执行过程:
1、先通过一个二级索引(create_date)筛选出需要的数据,这个没问题;
2、将筛选出的数据排序,不是有主键索引么?在这难道就走不上了?
第二步过程实际是:
1、通过第一步二级索引得到的主键列表
2、回表查询出筛选出记录的详细信息(这些信息在聚簇索引的叶子节点上)
3、将筛选出的数据排序(filesort)
解决办法:
不使用主键排序,使用查询条件 create_date字段来排序;
这样执行过程大概是:
1、根据create_date(索引)范围查询出合适记录;
2、根据排序方向,过滤出真正需要的数据(这还是二级索引数据集合)
3、回表查询步骤2索引列表的详细信息,并返回;
结论:
WHERE 子句使用的索引,没有在排序中使用到,就会出现filesort;