Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.1k views
in Technique[技术] by (71.8m points)

mysql在处理较大limit分页时候回表的疑问

假设我有个表t1
三个字段:id,c1,c2
c1上有普通索引

执行sql:
select * from test1 where c1>202 limit 10000,10

这样的查找,1-10010都要回表,最后把10000-10010数据返回,为什么mysql不是在索引上找到第10001个才开始回表进行数据读取,这样速度不就快了吗,前面的数据回表有什么意义?但是mysql不这么做肯定是有原因的,各位有没有什么好的解释?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

1、为什么需要回表:

通过了解sql语句的执行顺序可以知道为什么需要回表了,limit限制条数是在select投影列后才执行的,所以需要先执行select投影列,由于投影列字段在c1索引树上不能获取到全部,那就需要回表了;

查询sql语句的执行顺序可参考:

FROM
<表名> # 选取表,将多个表数据通过笛卡尔积变成一个表。
ON
<筛选条件> # 对笛卡尔积的虚表进行筛选
JOIN <join, left join, right join...>?
<join表> # 指定join,用于添加数据到on之后的虚表中,例如left join会将左表的剩余数据添加到虚表中
WHERE
<where条件> # 对上述虚表进行筛选
GROUP BY
<分组条件> # 分组
<SUM()等聚合函数> # 用于having子句进行判断,在书写上这类聚合函数是写在having判断里面的
HAVING
<分组筛选> # 对分组后的结果进行聚合筛选
SELECT
<返回数据列表> # 返回的单列必须在group by子句中,聚合函数除外
DISTINCT
<数据除重>
ORDER BY
<排序条件> # 排序
LIMIT
<行数限制>

2、解决方式:

可以将sql语句改成下面这样,就会避免大量回表了:
select b.* from (select id from test1 where c1>202 limit 10000,10)a, test1 b where a.id=b.id

首先在c1普通索引树上获取到limit限制的 id主键值,然后再根据主键值去聚簇索引树上查询出需要的数据即可;常见的分页sql语句一般也是这样写,往后翻页时速度跟翻第一页一样快;


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...