首页 > 编程语言 >java分页方案总结

java分页方案总结

时间:2024-09-21 19:21:42浏览次数:13  
标签:总结 场景 java 分页 查询 limit mysql 主键

  • 1 Limit Offset分页
  • 2 Limit 指定主键Id过滤
  • 3 HasMore 滚动查询
  • 4 ElasticSearch 分页查询

  ”使用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就没有其他方式避免深度分页吗?答案是可以

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 <lastMinId order by id desc limit 20;

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

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

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

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

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

3 HasMore 滚动查询

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

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

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

4 ElasticSearch 分页查询

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

值得一提的是需要mysql数据异构到ES,ES加载进索引也有1s左右延迟,数据从产生到ES索引延迟比较高。

ElasticSearch 支持分页查询,和Mysql Limit offset 类似。同时也强烈建议,使用分页查询时,指定排序方式。

SearchRequest searchRequest = new SearchRequest(index);
  SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
  //计算出记录起始下标
  int from = (pageNum - 1) * pageSize;
  // 起始记录下标,从0开始
  sourceBuilder.from(from);
  //每页显示的记录数
  sourceBuilder.size(pageSize);

和mysql类似,ES也有深度分页的查询压力,默认的最大查询深度max_result_window=1W, 阈值可以修改。在低频的B端查询场景,可以根据需要适当调整阈值。

以上4种分页查询方式没有最好,需要针对不同的场景选择最合适的。

标签:总结,场景,java,分页,查询,limit,mysql,主键
From: https://blog.51cto.com/maguobin/12075051

相关文章

  • Java笔试面试题AI答之单元测试JUnit(7)
    文章目录37.请列举一些JUnit扩展?1.参数化测试2.条件测试执行3.临时目录4.时间测试5.重复测试6.前置/后置条件7.Mockito8.SpringTest9.JUnitVintage10.Testcontainers11.自定义注解和扩展12.测试监听器(TestListener和RunListener)38.请列举Java程序员......
  • DsExcel, GcExcel FOR JAVA 7.2.2
    High-SpeedJavaExcelSpreadsheetAPILibraryDocumentSolutionsforExcel(DsExcel,previouslyGcExcel),JavaEdition,allowsyoutoprogrammaticallycreate,edit,import,andexportExcelspreadsheetsinyourJavaapplications.Deploynearlyanywhere.......
  • Java pom.xml 资源文件源的配置
    前两天在打maven包是遇见一个问题:打完包发现src/main/java中的的mapping没有被打包进去;原因主要是mapping目录里面的文件都是xml文件并不是.java文件,而maven打包默认的src/main/java的是Java文件,它不会打包里面的xml文件,所以在打包之后里面不会有mapping。解决方法:在pom.xml中配......
  • 算法实现:Java 回文数检测
    题目描述:给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。回文数:是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文数,而 123 不是。题目分析我们做这道题很容易可以想到:我们新建一个变量,这个变量里存放着一个颠倒的x然后用这个数去与我......
  • java 内存加载几个忆数据
    一:概述在现代软件开发中,随着数据量的不断增长,我们经常会遇到需要处理大规模数据的场景。Java,作为一种广泛使用的编程语言,其内存管理和数据处理能力受到了极大的考验。本文将探讨在Java中如何有效地加载和处理亿级数据,通过不同的方法来实现,并提供实际的案例分析。二:具体说明<1>内存......
  • 【Java】了解线程 Thread 类的使用,
    线程是什么线程是操作系统中调度的基本单位,是比进程更小的执行单元。线程在进程内部运行,共享该进程的资源,如内存和文件句柄,但每个线程都有自己的执行栈和程序计数器。线程的主要特点包括:轻量级:线程相较于进程更加轻量,创建和销毁的开销较小。共享资源:同一进程中的线程共享该进程的内......
  • Java解题:求商和余数
    题目:给定两个整数,被除数和除数(都是正数,且不超过int的范围)要求不使用乘法、除法和%运算符,得到商和余数。题目分析我们知道,除法的本质其实就是被除数对除数不断地进行减法运算。所以,我们只需要循环这个运算,同时记录循环了多少次,就可以得到商。而最终若不够减,那么此时的被除数即是......
  • JAVA集合——Collection接口
    目录1.Collection接口1.概述2.常见方法a.对象添加到集合中b.清空集合中所有的元素c.把给定的对象在当前集合中删除d.判断是否包含 e.判断集合是否为空f.返回集合元素中集合个数​编辑3.Collection的遍历方式a.迭代器遍历1.获取迭代器2.迭代器中常见的方法a.......
  • Java泛型(JDK5)
    目录1.概述2.泛型的优点3.泛型类4.泛型方法5.泛型接口1.实现类给出具体的类型2.实现类延续泛型,创建实现类对象时再确定类型6.泛型的通配符1.概述泛型是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查注意:泛型只能支持引用数据类型2.泛型的优点1.......
  • Java中的输入输出:深入解析与应用
    Java中的输入输出:深入解析与应用在Java编程中,输入输出(I/O)是处理数据流动的核心机制。无论是从控制台读取用户输入,还是从文件中读取数据,或是将数据写入文件,Java都提供了丰富的I/O类和方法来实现这些操作。理解Java中的输入输出机制,对于编写高效、可靠的程序至关重要。本文将......