You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于MySQL延迟连接优化中二级索引读取逻辑的疑问

关于MySQL延迟连接优化的两个疑问

假设表t的主键为pk,列x有唯一索引,表中包含其他若干列。原查询与优化后的延迟连接查询如下:

-- 简单查询
select * from t order by x limit 500, 20;

-- 优化后的延迟连接查询
select * from t join (
  select pk from t order by x limit 500, 20
) dt using(pk);

原文提到:即使x列有唯一索引,简单查询中MySQL仍需读取500+20条完整行(并丢弃前500条),因为该二级索引仅包含x列和隐含在末尾的pk列。针对此结论有两个疑问:

  1. 作者是否指前500条数据的完整行都会被读取?
  2. 若确实如此,原因是什么?若仅读取第500条之后的20条,二级索引难道不能只读取这20条对应的pk吗?

问题1解答

是的,作者的表述完全准确:前500条数据的完整行确实会被MySQL读取出来,之后直接丢弃,仅保留后面20条返回给请求方。

问题2解答

核心原因在于MySQL处理limit offset, rows的执行逻辑:

  • 当执行select * from t order by x limit 500,20时,MySQL会先利用x的唯一索引完成排序,这个二级索引里只存储x和pk的值。
  • 但因为查询语句要求返回所有列(*),MySQL必须获取完整的行数据。所以它会按照二级索引的顺序,依次取出前500+20条对应的pk,并立即通过pk去聚簇索引(主键索引)中回表查询完整行数据。
  • 为什么不能直接跳过前500条,只取后面20条的pk回表?因为limit 500,20的逻辑本质是“先获取520条数据,再截断前500条”。MySQL的执行器必须遍历到第500条的位置,才能确定后续要获取的20条数据的pk值。而在遍历过程中,由于查询要求返回所有列,它无法只停留在二级索引层面,必须每遍历一条就回表取出完整行,直到凑够520条数据后再做截断处理。

而优化后的延迟连接查询,先通过子查询仅获取pk:子查询只需遍历x的二级索引,拿到520个pk后丢弃前500个,仅保留20个有效pk,再用这20个pk去回表查询完整行。这样就把回表次数从520次降到了20次,大幅减少了IO开销,这也是延迟连接优化的核心逻辑。


内容的提问来源于stack exchange,提问作者MeYokYang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 19:52:40