大表分页查询执行计划成本高但运行快,是否属于低效查询
结论
该查询并不低效,EXPLAIN结果的预估值和实际执行表现不一致是MySQL优化器预估逻辑的固有特性导致的,只要实际执行速度符合业务要求,无需额外调整。
原因解释
- EXPLAIN输出的
rows、cost字段都是优化器基于表统计信息生成的预估值,不是运行时实际消耗的资源、扫描的行数,不能单独作为判断查询效率的依据。 - 你用的是标准的Keyset(游标)分页写法,断点条件
(a.updated_ts > 'some time' or (a.updated_ts = 'some time' and a.id > x))和排序逻辑order by a.updated_ts, a.id完全匹配,加上InnoDB二级索引idx_name(updated_ts)的叶子节点默认携带主键id,所以可以直接从断点位置开始按索引顺序扫描,不需要做额外排序,也不需要跳过大量偏移行。 - 优化器做成本预估时,无法准确判断
field1 = 'VALUE'这个过滤条件在索引有序序列中的分布密度,会默认按照最坏情况估算:需要扫描大量符合时间+id范围的行,才能凑够limit 100要求的结果数,因此给出的预估成本、预估rows会非常高。但实际运行中只要符合field1 = 'VALUE'的行分布不极端,通常只需要扫描很少的索引项就能凑够100条结果,执行速度自然很快。
验证方式
可以在执行查询前运行flush status;,查询结束后运行show status like 'Handler_read_next';,如果返回的数值只比100高一点,就说明实际扫描的行数非常少,查询效率符合预期。
可选优化(非必须)
如果担心极端场景下(比如符合field1 = 'VALUE'的行分布非常稀疏)扫描行数过多,可以把二级索引调整为复合索引:
alter table t_dummy drop index idx_name, add index idx_updated_ts_field1(updated_ts, field1, id);
调整后field1的过滤可以直接在索引层面完成,不需要回表判断,优化器的成本预估也会更准确,不过如果当前查询执行速度已经满足业务要求,完全不需要做这个改动。
内容的提问来源于stack exchange,提问作者user3621726
相关产品推荐
相关产品推荐

