[数据库/PostgreSQL] 真的没有完美的分页方法吗?

2022-03-14 13:26:03 +08:00
 kaifeiji
因为性能原因,研究了很多分页 SQL 的实现:

1 、limit-offset 的耗时线性增长;
2 、keyset 不能跳转指定页;
3 、xmin 基于事务,可能有“空洞”;
4 、ctid 基于存储,不能用 where 条件过滤;
5 、pg_stats 基于统计数据,实时性差,结果不精确。

具体可参考这篇文章:

https://kaifeiji.cc/post/do-i-really-know-about-pagination/

我想问的是,有没有:

1 、耗时固定
2 、能跳转指定页
3 、没有“空洞”
4 、能用 where 条件过滤
5 、实时性、结果精确

的分页方法?
6141 次点击
所在节点    PostgreSQL
41 条回复
kaifeiji
2022-03-14 16:43:39 +08:00
@sfqtsh 明白你的意思了,MOVE absolute 确实可以跳转到指定页,但它的实现和性能与 limit-offset 是相同的,所以耗时也是线性增长
hooopo
2022-03-14 16:44:24 +08:00
还是有的
3dwelcome
2022-03-14 16:57:24 +08:00
@kaifeiji "但它的实现和性能与 limit-offset 是相同的,所以耗时也是线性增长"

基本上好一点的网站,翻页都是有限制的,用户也不可能无限翻下去。无限翻页就是个伪需求。

头 100 页内存缓存一下,基本上能应付 95%的情况。剩下的 5%,也不会强制要求高性能。

坚持说数据库 limit-offset 性能有问题的,不是傻就是坏。
9c04C5dO01Sw5DNL
2022-03-14 17:02:23 +08:00
es 也没有完美分页
kaifeiji
2022-03-14 17:13:07 +08:00
@3dwelcome 懂了
Oktfolio
2022-03-14 19:32:33 +08:00
搜索引擎一定条数之后不是也只能游标分页吗?
felixcode
2022-03-14 19:45:27 +08:00
文章的最后
==========
P.S

最终,发现问题的根源是索引损坏,导致分页时排序太慢。

修复索引后,耗时 1 秒以内——千万级的数据分页,LIMIT-OFFSET 还是 HOLD 住的。

也就是说,我前边整的活儿算是白折腾了。
===========
Sasasu
2022-03-14 20:01:08 +08:00
有些奇葩 ORM 发出来的查询长这样:

select count(*), * from (<query>) limit 20

这种人现在的计算机科学还满足不了他
hooopo
2022-03-14 20:07:53 +08:00
@Sasasu 不信
ClarkAbe
2022-03-14 21:26:39 +08:00
mysql limit page 现在差不多 300 万订单数据了还是很快的啊,毫秒级响应.......
hope4tomorrow
2022-03-14 23:07:30 +08:00
@MoYi123 因为原有的主键索引失效了,失效原因是,那个表是开发环境的日志表,组里有同学操作过,删除了一些数据,导致索引也失效了,所以再建一次索引,leader 当时的描述是,建一个二级索引
ipwx
2022-03-15 00:11:42 +08:00
ES 的底层是 Lucence ,LUCENCE 在我当年学习的时候,分页原理应该是直接用关键词抽出来一些倒排索引,然后用优先队列对倒排索引进行合并,上面的结果打分以后用一个大小为 K * page_size 的堆保存最好的前 K 页结果然后返回第 K 页的内容。
msg7086
2022-03-15 05:51:03 +08:00
@ipwx 提醒一下,是 Lucene 不是 Lucence 。以前我也读错写错过。
encro
2022-03-15 09:05:20 +08:00
分页关键点:

1 ,数据量大情况下不要 count ;
2 ,复杂查询用 es 之类;
3 ,索引排序;
4 ,组合索引;
5 ,索引类别;
6 ,explain ;
Geekerstar
2022-03-15 13:55:49 +08:00
@leoskey 哈哈哈,被老哥鞭尸了
Sasasu
2022-03-15 14:26:20 +08:00
@hooopo 随便一个搜索引擎搜 '分页组件是基于 Mybatis 的,它会在你写的 SQL 脚本外面再套一层 SELECT COUNT(*) ROWNUM_ FROM (….) 计算总记录数,同时有另一个嵌套 SELECT * FROM(…) WHERE ROWNUM > 10 AND RONNUM < 10 * 2 这种方式生成分页信息'
hooopo
2022-03-15 14:37:36 +08:00
@Sasasu 这种方式很高效啊
Sasasu
2022-03-15 21:51:37 +08:00
@hooopo 带着 filter 算总页数了
hooopo
2022-03-15 22:20:54 +08:00
@Sasasu 并不是总页数 只是判断有没有下一页 盲猜做无限下拉的
KouShuiYu
2022-03-30 17:08:18 +08:00
limit-offset 还有一个坑必须加上 order 且排序要唯一,不然查出来的顺序会随着 limit-offset 参数不同而变化🐶

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

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

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

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

© 2021 V2EX