Spring:项目中常见的四种分页方案!
一、前言
分页查询技术概览
分页查询技术是一种数据库查询技术,通过将大量数据分成多个较小的部分(即页)来提高查询效率和用户体验。以下是项目中常见的四种分页方案的详细介绍。
二、分页方案
一、Limit Offset分页
案例分析:
小型应用程序或数据量不大的场景。
例如:通过SQL语句中的LIMIT和OFFSET子句实现分页。例如,查询第三页的数据(每页10条),SQL语句为:LIMIT 20,10。
select * from t_student where 查询条件 order by id desc limit 100,10;
limit offset 实现简单,但是存在缺陷。当出现深度分页时,MySQL 需要扫描大量数据才能找到指定页的数据,造成慢查询 ,增加增加数据库的内存和cpu负载, 如果这个深度分页的QPS比较高,无疑最终会拖垮数据库。
在流量高峰期,如果深度分页的慢查询较多,毫无疑问,会增加其他SQL耗时,影响其他业务场景。值得说明的是,分页查询必须指定排序方式。如果没有指定排序方式,使用分页很难保证数据不会出现重复。 如果实在没有排序字段,可以使用主键ID。
二、Limit 指定主键Id过滤
案例分析:
数据量较大,且可以指定主键ID进行排序的场景。
实现方式:在查询条件中指定上一轮最小的ID,以限制查询范围。例如,查询下一页数据时,指定id < lastMinId。
假设students表有一个自增主键id。
查询第一页数据时,不指定lastMinId。
查询后续页面时,将上一页数据中的最小ID作为lastMinId传递给查询语句:
SELECT * FROM students WHERE id < lastMinId ORDER BY id DESC LIMIT 20。
对方式一查询方式的调整为:
调整前
select * from t_student where 查询条件 order by id desc limit 100,10;
调整后
select * from t_student where 查询条件 AND id < lastMinId order by id desc limit 10;
这种方式前提条件是排序方式可以指定主键Id,如果根据其他排序方式,就不能这样做了。
三、HasMore 滚动查询
案例分析:
如用户App端的购买记录页,用户只能每页滚动查询购买记录,无需知道购买订单总数。
实现方式:每次查询时,多查询一条数据(即每页数量+1)。如果返回的数据条数等于指定的页数+1,则表示还有更多数据,继续查询下一页;否则,表示没有更多数据。
实例:
假设每页查询10条购买记录。
第一次查询时,指定查询11条数据:
SELECT * FROM purchases LIMIT 11。
如果返回11条数据,表示还有更多数据,继续查询下一页;否则,表示没有更多数据。
优点:无需获取总页数,减少了SELECT COUNT(*)的查询开销。
缺点:无法实现页数跳转。
四、ElasticSearch 分页查询
案例分析:
检索条件复杂、实时性要求比较低的查询场景,如B端的各类复杂查询条件检索场景以及C端用户关键词订单列表搜索等。
实现方式:使用ElasticSearch的from和size参数实现分页查询。 同时也强烈建议,使用分页查询时,指定排序方式。
实例:
假设有一个名为orders的索引,包含大量订单数据。
使用ElasticSearch分页查询第一页的数据:
GET orders/_search { "from": 0, "size": 10, "sort": [ { "order_date": { "order": "desc" } } ] }。
查询后续页面时,调整from参数的值:
GET orders/_search { "from": 10, "size": 10, "sort": [ { "order_date": { "order": "desc" } } ] }。
优点:支持复杂的检索条件,查询性能较高。
缺点:和mysql类似,ES也有深度分页的查询压力,默认的最大查询深度max_result_window=1W, 阈值可以修改。在低频的B端查询场景,可以根据需要适当调整阈值,但过深的分页可能导致性能问题。
三、总结
在实际应用中,应根据具体需求和场景选择合适的分页方法。对于小型数据集,Limit Offset 分页查询可能是一个简单而有效的选择;对于具有唯一自增主键的表,可以考虑使用 Limit 指定主键 Id 过滤分页;对于需要实时滚动加载数据的场景,HasMore 滚动查询可能更为合适;而对于需要全文搜索或处理大规模数据集的场景,ElasticSearch 分页查询则是一个强大的工具。