limit mysql 取最后_分页场景(limit,offset)特别慢,有什么办法可以优化?

2021-06-07 14:19:21 +08:00
 aries910

目前的场景就是 单表大概 20 万左右的数据,需要分页,排序(浏览量、新增时间,点赞等等) laravel 生成的 sql select id, logo, title, supports, collections, created_at, views, user_id, summary from table where status > 0 order by supports desc, created_at desc limit 20 offset 164920;

因为 offset 就执行的很慢 求大牛给点解决方案加速下,最好就是通过修改 sql 的方式

PS:机器是单核小主机。。。

2730 次点击
所在节点    问与答
39 条回复
lostvincent
2021-06-07 17:03:07 +08:00
相关知识 https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
#1 方法是可以的,你还是慢可能是哪里没写对

步骤 1: select id where {condition};
步骤 2: select * where id in (步骤 1 查出来的);

最关键是步骤 1 只 select id,顺带 where 相关的字段的索引安排
aries910
2021-06-07 17:19:10 +08:00
emeab
2021-06-07 17:35:23 +08:00
@aries910 我这边 500 万单表 都没问题. 1s 多.
emeab
2021-06-07 17:36:06 +08:00
我半桶水解决不了. 等大牛把.
JasonLaw
2021-06-07 17:41:19 +08:00
还是在附言上添加一下 expalin 的结果吧。没有足够的信息,所有人都是靠猜的。
Amit
2021-06-07 17:42:59 +08:00
楼上先查出 id 再关联查询数据应该是最好的办法了,limit 写在子查询中只查 id 查的是索引没有回表,小主机应该也是没问题的啊,楼主要不要再检查下
mikeguan
2021-06-07 17:56:44 +08:00
取消分页吧。
我们最终采用分页时最多读取 1 万条数据
数据量大了,分页真的扛不住
napsterwu
2021-06-07 18:04:28 +08:00
因为如果有 20w 数据,offset 19w,也会遍历 19w 行。只能是用 id 去过滤
zpfhbyx
2021-06-07 18:45:38 +08:00
#2 正解
calpes
2021-06-07 19:20:41 +08:00
这楼里一群人干哈呢,1 楼就是完美解决方案了,查到后边 offset 大了慢是因为你表里有 text,先查 id 再取其他字段就 ok 了
calpes
2021-06-07 19:24:34 +08:00
@emeab 二次执行就快了可还行,查完一次就有缓存了
emeab
2021-06-07 19:59:45 +08:00
@calpes 所以我说我是半桶水啊 XD
dawniii
2021-06-07 20:12:47 +08:00
楼上很多说先取 id 的,只取 id 的话,是不用 offset 条件了吗?慢的原因不就是 offset 的值太大了,问题不还是存在吗?
ebingtel
2021-06-08 09:33:14 +08:00
@emeab 有的时候 不一定是 offset 慢,先看看把 orderby 去掉,是不是快了……如果是 orderby 的原因,相关字段加上索引……如果没走索引,再用 FORCE INDEX
aries910
2021-06-08 09:39:39 +08:00
@emeab 不管问题有没有解决,也还是感谢你的建议 :),至少看的来你是真的帮忙去实践了,谢谢!
aries910
2021-06-08 09:45:26 +08:00
@ebingtel 确实是的,上面有很多小伙伴提议先用 id 取区间,再 select 完整数据
这种方法时好时坏,我替换了 orderby 后也会变快
关键查资料的时候看到个说法 :
where status=1 orderby views desc
这种情况这种会用一个索引,就算 status 和 views 都索引了,也并没啥用
求确认
xiaochong0302
2021-06-08 15:16:45 +08:00
只能看前 N 页就好了,简单粗暴

```
public function getPage()
{
$page = $this->request->getQuery('page', ['trim', 'int'], 1);

return $page > 100 ? 100 : $page;
}

public function getLimit()
{
$limit = $this->request->getQuery('limit', ['trim', 'int'], 12);

return $limit > 100 ? 100 : $limit;
}
```
ebingtel
2021-06-09 09:37:25 +08:00
@aries910 如果是 orderby 多个字段,可以建立一个复合索引,这样才会快……如果没有,就这用用 FORCE INDEX
ebingtel
2021-06-09 09:38:40 +08:00
@ebingtel (建立复合索引的基础上)就接着用 FORCE INDEX

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/781896

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX