
目前的场景就是 单表大概 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:机器是单核小主机。。。
1 loophole12 2021 年 6 月 7 日 via Android 可以先把拉取的 id 都取出来,再根据 id 用 in 拉取整行数据 |
2 sheeta 2021 年 6 月 7 日 取上次分页最后的结果 id, > id limit 20 。缺点,不能跳到指定的页。 |
3 ksedz 2021 年 6 月 7 日 加索引试试 |
4 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 Select * From table_name Where id in (Select id From table_name where status > 0) order by supports desc, created_at desc limit 20 offset 164920; |
5 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 不过 20 万就干趴下 看看慢日志 |
8 aries910 OP @loophole12 试过了,没啥用 |
9 aries910 OP @ksedz 上面的 status 和 supports 都加了单独的索引,没啥用给,我看网上有人说 mysql 查询的时候,where 和 order 只会用一个索引,所以就算都有索引也没用,我去尝试了也确实没用(我不太考虑复合索引,毕竟小机器,怕后面数据更大了更新索引占资源) |
10 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 @aries910 SELECT * FROM table INNER JOIN( SELECT id FROM table status > 0 order by supports desc, created_at desc LIMIT 10000,100 ) b USING(id) 试下? 我这边单表快 40 万, 也就 0.1 秒 |
11 Jooooooooo 2021 年 6 月 7 日 大数分页是无解问题 一个妥协的方案是用 id 当游标 |
14 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 @aries910 我这边二次执行就快了. |
15 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 |
16 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 这个也行. 因为没完整的表 只能这样了. |
18 cnoder 2021 年 6 月 7 日 楼上方法叫 延迟关联 |
19 notejava 2021 年 6 月 7 日 思路拓宽一点,从查询流程上优化,例如提前然用户填筛选条件筛选掉部分数据,再做分页。 |
20 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 @aries910 explain 看下索引 |
21 lostvincent 2021 年 6 月 7 日 相关知识 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 相关的字段的索引安排 |
23 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 @aries910 我这边 500 万单表 都没问题. 1s 多. |
24 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 我半桶水解决不了. 等大牛把. |
25 JasonLaw 2021 年 6 月 7 日 还是在附言上添加一下 expalin 的结果吧。没有足够的信息,所有人都是靠猜的。 |
26 Amit 2021 年 6 月 7 日 楼上先查出 id 再关联查询数据应该是最好的办法了,limit 写在子查询中只查 id 查的是索引没有回表,小主机应该也是没问题的啊,楼主要不要再检查下 |
27 mikeguan 2021 年 6 月 7 日 via Android 取消分页吧。 我们最终采用分页时最多读取 1 万条数据 数据量大了,分页真的扛不住 |
28 orcusfox 2021 年 6 月 7 日 via iPhone 因为如果有 20w 数据,offset 19w,也会遍历 19w 行。只能是用 id 去过滤 |
29 justseemore 2021 年 6 月 7 日 #2 正解 |
30 calpes 2021 年 6 月 7 日 这楼里一群人干哈呢,1 楼就是完美解决方案了,查到后边 offset 大了慢是因为你表里有 text,先查 id 再取其他字段就 ok 了 |
32 2kCS5c0b0ITXE5k2 2021 年 6 月 7 日 @calpes 所以我说我是半桶水啊 XD |
33 dawniii 2021 年 6 月 7 日 楼上很多说先取 id 的,只取 id 的话,是不用 offset 条件了吗?慢的原因不就是 offset 的值太大了,问题不还是存在吗? |
34 ebingtel 2021 年 6 月 8 日 @emeab 有的时候 不一定是 offset 慢,先看看把 orderby 去掉,是不是快了……如果是 orderby 的原因,相关字段加上索引……如果没走索引,再用 FORCE INDEX |
36 aries910 OP @ebingtel 确实是的,上面有很多小伙伴提议先用 id 取区间,再 select 完整数据 这种方法时好时坏,我替换了 orderby 后也会变快 关键查资料的时候看到个说法 : where status=1 orderby views desc 这种情况这种会用一个索引,就算 status 和 views 都索引了,也并没啥用 求确认 |
37 xiaochong0302 2021 年 6 月 8 日 只能看前 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; } ``` |