以前在数据中写翻页的代码时,一直把sql写成这样
SELECT * FROM table_name ORDER BY id ASC LIMIT 10 OFFSET 10
也就是用LIMIT
和OFFSET
来控制需要输出的内容区域,后来我在翻其他人代码时看到了这种写法
SELECT * FROM table_name WHERE id > 10 ORDER BY id ASC LIMIT 10
这种写法是否比前一种写法的速度要更快,因我看到它使用id主键的索引,而且还把检索区域用id > 10
缩小了,理论上应该更快。但这种写法应该也有一定的局限性,比如最大的局限就是它只能用于那种类似timeline的,从第一页往后翻的应用场景,因为你要翻下一页必须知道前一页的最后偏移是多少。
不知道我这样的分析是否正确,各位有什么样的看法。
为了方便描述,下面id即指用来排序的字段
使用id > n 的方式,有局限性,但没有 @qinjianxiang 说的那么大。对于id不连续的问题,可以通过翻页的时候同时传入最后一个id方式来解决。比如:
这种方式比较大的缺点是,如果在浏览中有插入/删除操作,翻页不会更新,而总页数可能仍然是根据新的count(*) 来计算,最终可能会产生某些记录访问不到。为了修补这个问题,可以继续引入当前页码以及在上次翻页以后是否有插入/删除等影响总记录数的操作并进行缓存。
MySQL里对LIMIT OFFSET的处理方式是,取出OFFSET+LIMIT的所有数据,然后去掉OFFSET,返回底部的LIMIT。
所以,在OFFSET数值较大时,MySQL的查询性能会非常低。
MySQL会取出20条数据,只返回后10条。
利用id索引,MySQL只取出10个结果,返回。这种做法却是要求连续翻页,不能跳页,受约束。
暂时没有更好选择,where id > :id的方式局限性太大,id不一定是连续的,翻页也不见得是根据主键来翻。
limit offset从功能上来讲是非常好的,如果担心offset过大时耗时太长,可以分库分表。或者用搜索引擎
看到过一篇总结的比较全的文章:http://www.dewen.org/q/20/
楼主的理解是对的。用id>m limit n 比用 limit m,n 快很多,主要原因是limit m,n需要去读取前面的m条记录。
如果是翻页需求,就在返回结果中取到最后的一个,再传给下一个链接。 @Rodin 给的方案就很好。
可以两种方式相结合,id>x limit m,n