专栏名称: Java基基
一个苦练基本功的 Java 公众号,所以取名 Java 基基
目录
相关文章推荐
北京药监  ·  北京药品医疗器械创新服务站咨询安排(2025 ... ·  15 小时前  
北京药监  ·  北京药品医疗器械创新服务站咨询安排(2025 ... ·  15 小时前  
BRTV建外14号  ·  本周起,北京地铁3号线、12号线、19号线有 ... ·  21 小时前  
BRTV建外14号  ·  本周起,北京地铁3号线、12号线、19号线有 ... ·  21 小时前  
ZOL中关村在线  ·  买了就是大冤种?iPhone ... ·  昨天  
EETOP  ·  HotChips 2024 论文及资料全集 ·  2 天前  
51好读  ›  专栏  ›  Java基基

四种分页方案,哪种分页效果更好?

Java基基  · 公众号  ·  · 2024-12-27 11:55

正文

👉 这是一个或许对你有用 的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入 芋道快速开发平台 知识星球。 下面是星球提供的部分资料:

👉 这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本

来源:juejin.cn/post/
7275563321616629779


”使用mysql limit 分页就行了,分页查询用得着四种写法吗? "

这可能是很多人的想法。的确mysql limit offset是可以胜任分页的,但是另外三种办法在其他场景表现更好。

大家最熟悉的就是如下的分页截图,返回总页数、支持页数跳转。

1 Limit Offset分页

例如每页10条,查询第三页 ,mysql limit 部分为:limit 20,10;

前段每次需要指定 每页数量,当前页数。由后端拼接查询SQL,构建mysql limit 子句。

limit offset 分页有几个特性。

  1. 支持页数跳转。用户选定第几页,就跳转到对应的页面。
  2. 返回记录总条数。用户可以看到共几页,一共多少条数据。

limit offset 实现简单,但是存在缺陷。 当出现深度分页时,MySQL 需要扫描大量数据才能找到指定页的数据,造成慢查询 ,增加增加数据库的内存和cpu负载, 如果这个深度分页的QPS比较高,无疑最终会拖垮数据库。在流量高峰期,如果深度分页的慢查询较多,毫无疑问,会增加其他SQL耗时,影响其他业务场景。

值得说明的是, 分页查询必须指定排序方式。如果没有指定排序方式,使用分页很难保证数据不会出现重复。 如果实在没有排序字段,可以使用主键ID。

我曾经犯过类似错误,在使用ElasticSearch替换lucene 做检索时,发现lucene和ElasticSearch返回的结果一直不一致,排查了很久,才意识到必须指定排序方式,否则使用分页查询会导致数据重复。

那么Limit Offset就没有其他方式避免深度分页吗?答案是可以

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

2 Limit 指定主键Id过滤

如果在查询条件上加上主键Id是不是就可以了呢?

改进前:

select * from students where xxxx查询条件xxx order by id desc limit 1000,20;

改进后:

select * from students where xxxx查询条件xxx AND id order by id desc limit 20;

改进后在原有的查询条件上 指定了lastMinId,上一轮最小的Id。在查询下一页时,把上一页的最小id 传下去,这样保证后续查到的列表都是小于lastMinId。从源头上增加了查询条件,减少了mysql的检索范围,每次都只获取前二十条数据。

这样就高枕无忧了吗?当然不

这种方式前提条件是排序方式可以指定主键Id,如果根据其他排序方式,就不能这样做了。

这种方式还有其他应用场景吗?最佳的场景就是从下游批量获取大量数据时,可以根据主键id进行排序,每次选择最大的N条,或最小的N条。

每次查询都更新主键id范围,这样就能避免深度分页,查询全部的数据。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

3 HasMore 滚动查询

有的业务场景例如用户App端的购买记录页,用户只能每页滚动查询购买记录,无需知道购买订单总数。针对这个场景,有什么优化呢?

在之前的limit Offset分页时,需要返回记录总数,前端也要确定查询总页数。滚动分页查询则无需获取总页数,无需查询总数。减少了一次 select count(*) 的查询。

只需要在每一次分页查询时,每页数量+1 即可。例如每页10条,可以指定11条,如果真查出来11条, hasMore=true ,上游需要继续查,否则 hasMore=false ,上游无需再分页查询。

4 ElasticSearch 分页查询

ES 比较适用于检索条件复杂、实时性要求比较低的查询场景。例如B端的各类复杂查询条件检索场景以及 C端用户关键词订单列表搜索等场景。查询耗时基本在100ms以上、甚至1s以上。







请到「今天看啥」查看全文