对比:MySQL与Elasticsearch深分页问题的解决方案

上周我的朋友正在研究数据库深度分页问题。
他表示,在MySQL中,当每页显示1 0条数据,搜索到第1 000页时,理论上需要返回表1 0001 0次,但实际上只需要1 0次。
这让我想起了子查询优化、惰性INNERJOIN分配、标签记录方法、使用between...and...等优化方案来转换限制查询。

2 02 3 年,我发现他还在讨论Elasticsearch的深度分页问题。
他表示,在ES中,搜索过程包括查询和检索阶段,但深度分页会导致大索引量的性能问题。
ES提供了scroll、scrollscan、slicedscroll和search_after方法来优化这个问题。
他特别提到了scroll方法,可以管理快照,适合大数据量的非实时处理。

我的朋友在ES7 中也提到了这一点。
版本中,官方不再推荐scroll方法,而是推荐带有PIT的search_after方法。
他表示,使用search_after和PIT可以避免服务器过载,并保证查询数据的一致性。

我只是想起了一些别的,他总结说:无论是MySQL还是Elasticsearch,深度分页问题都需要优化查询策略,减少表返回次数,使用索引或者某些方法来提高性能,降低服务器负载。
必须避免深层分页问题,​​并选择适当的方法来提供高效、准确的查询结果。
算了,你自己想办法吧。

MySQL深分页问题原理与三种解决方案

说实话,我在做电商后端系统的时候,就面临过一个严重的深度分页问题。
当时,用户正在检查数百页的产品,数据库被堵塞。
后来,随着我慢慢的探索,我发现我其实有几个方向可以走。

第一个想法,说实话有点违反直觉,是限制用户可以拉出的页面数量。
我记得我借用了淘宝,当超过5 0个页面时,直接提示用户,“兄弟,你太过分了,你为什么不不同情况下再搜索一下呢?”这是因为随着页面数量的增加,相关性肯定会降低,但用户就是喜欢这样做,即使很努力也无法忍受。
MySQL在这里可以玩个花招,比如给查询参数添加1 000的限制。
如果超过这个数,就会返回空结果,或者提示用户更改关键字。

有趣的是,第二种方法更实用。
当时有一张表,里面有很多字段。
我运行了一个选择...分页。
当我查看执行计划时,发现排序是在非索引字段上进行的。
后来改了SQL,把排序字段改成了主键,就花了几秒钟。
当我看到实施方案时印象特别深刻。
例如,附加项中有一些术语,如“使用索引”或“使用位置”,它们通常隐藏优化的关键。
我记得有一个项目我多次运行“解释分析”,发现当连接顺序颠倒时,时间从 5 秒下降到 1 秒。

第三种ID寻呼,我认为是最实用的。
例如,当您检查 Users 表时,不要使用范围 1 0 偏移量 1 00。
而是使用“ORDER BY WHERE ID > 1 00 ID ASC LIMIT 1 0”。
我之前也有一个项目。
更改偏移分页后,查询时间从几分钟直接减少到毫秒。
最主要的是确保ID是连续的并且没有空值。
在调试时,我添加了一个日志来检查每个查询的 ID 范围,以确保没有丢失数字。

在具体实现上,MyBatis 给了我很大的帮助。
我记得写过一个分页插件,直接在XML中添加,然后就变成了ID分页。
有朋友写了一个现成的插件,直接修改MyBatis的rowbounds。
它非常容易使用。
代码大概是这样的:
java @Select("从表中选择,其中 id > {startId} order by id asc limit {page size}") List findByPage(@Param("startId") long startId, @Param("pageSize") int pageSize);
其实深度分页的关键还是要看业务场景。
对于一些基于时间的查询,只需使用时间戳分页即可;对于一些基于用户行为的查询,使用 userid 增量进行分页是最合适的。
我尝试了几种解决方案,发现更改ID分页后,服务器CPU负载直接降低了一半。

我记得数据在附近检查你的周围环境。
我这里有一个项目。
更改分页后,用户报告“查询速度更快,而且我实际上可以同时打开三个分页”。
坦白说,这种体验的提升比仅仅看 SQL 执行时间有趣得多。