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

科技   2024-11-07 11:01   山西  
今天我们来聊聊一个非常经典的问题:分页方案
分页几乎无处不在,尤其是对于处理大量数据时,不分页就等于在玩命。不同的分页方案有各自的优缺点,选错了,不仅会让你的应用变得很慢,还会让用户体验一落千丈。
好了,废话少说,今天我就带大家一起来看看四种常见的分页方案,分别是:Limit Offset分页Limit+主键Id过滤HasMore滚动查询ElasticSearch分页查询。我会结合我的一些实际经验,分析它们的优劣,并给大家提供一些实用的代码示例。

1. Limit Offset分页:经典老套,但也有其合理性

首先,我们得说一下最常见的分页方式——Limit Offset分页。基本上,任何数据库的查询都可以用这个方案。你会在SQL语句中看到类似这样的一行:
SELECT * FROM users LIMIT 10 OFFSET 20;
这条SQL查询会从users表中取出20条记录之后的10条。是的,听起来很简单,但别小看这方案。

优点:

  • 实现简单,所有的数据库都支持,几乎没有门槛。
  • 适用于数据量不大的情况,性能还不错。

缺点:

  • 一旦数据量大,查询效率就会下降。因为数据库需要跳过OFFSET前的记录,做了很多无用的工作。
  • 如果数据被删除或者新增,页码可能不稳定。例如,在你分页的过程中,用户删了几条记录,你可能会看到重复的数据或者漏掉一些数据。

2. Limit + 主键Id过滤:不再“跳跃”,直接定位

为了解决Limit Offset分页的缺陷,很多项目开始使用Limit + 主键Id过滤分页。与传统的OFFSET分页不同,这种方式是通过上一页的最后一个主键id作为分页的基准,来查询下一页的数据。例如:
SELECT * FROM users WHERE id > 100 LIMIT 10;
这条SQL语句的意思是:取出id大于100的10条记录。通过这种方式,数据库不再跳过大量的记录,而是直接定位到数据的位置。

优点:

  • 性能更高,尤其是对于大数据量的表,因为不需要做OFFSET操作。
  • 稳定性好,不会因为数据插入或删除而导致重复或丢失。

缺点:

  • 需要在应用层维护一个“上次查询的最后一个ID”,而且通常分页是基于顺序查询的(按id的升序或降序),可能不适合某些复杂的排序需求。
  • 这种方式不适用于非主键排序的场景。

示例:

-- 第一次查询
SELECT * FROM users WHERE id > 0 LIMIT 10;

-- 第二次查询
SELECT * FROM users WHERE id > 10 LIMIT 10;

-- 第三次查询
SELECT * FROM users WHERE id > 20 LIMIT 10;

3. HasMore 滚动查询:更接近“无缝分页”的体验

HasMore滚动查询是目前很多产品中使用的分页方案,尤其是在移动端或者前端需要实现“滚动加载”的情况下。它的基本原理是:客户端只请求当前的数据,如果有更多数据,会返回has_more=true,表示是否有下一页。例如:
{
  data: [...], // 当前页数据
  has_moretrue // 是否还有更多数据
}

优点:

  • 用户体验非常好,尤其是在移动端,滚动加载能够让用户获得流畅的体验。
  • 适合用于实时数据展示,因为每次请求的数据是基于当前数据“增量”的。

缺点:

  • 需要在服务端维护状态,判断是否有更多数据。
  • 如果你需要回到某个具体页,滚动分页就有点“力不从心”了。比如要跳转到第10页,那就不太方便了。
  • 如果数据量很大,可能会遇到性能瓶颈,特别是当数据插入或者删除时,可能导致数据丢失或重复。

示例代码:

def get_paginated_data(last_seen_id):
    query = f"SELECT * FROM users WHERE id > {last_seen_id} LIMIT 10"
    results = execute_query(query)
    
    if len(results) < 10:
        has_more = False
    else:
        has_more = True

    return results, has_more

4. ElasticSearch分页查询:专业级搜索引擎的分页能力

ElasticSearch(ES)作为一个搜索引擎,不仅仅能处理高效的全文搜索,它的分页查询也非常强大。ES通过fromsize来做分页:
{
  "query": {
    "match_all": {}
  },
  "from"20,
  "size"10
}
这种方式本质上是和Limit Offset类似的,但它处理的是文档而不是传统数据库的表数据。

优点:

  • 性能非常好,尤其是在海量数据查询的情况下,ElasticSearch本身就是为了应对这类问题而设计的。
  • 支持更为复杂的查询、聚合和排序操作,可以在查询结果中进行多维度筛选。
  • 适合高并发查询,尤其是实时数据和大数据量的检索。

缺点:

  • 配置和维护成本较高,ElasticSearch不像普通数据库那样容易上手,需要专业的运维。
  • 如果没有合理的索引规划,性能也可能大打折扣。

示例代码:

from elasticsearch import Elasticsearch

es = Elasticsearch()

def search_paginated_data(query, page_size, page_num):
    start = (page_num - 1) * page_size
    body = {
        "query": {
            "match_all": {}
        },
        "from": start,
        "size": page_size
    }
    
    response = es.search(index="users", body=body)
    return response['hits']['hits']

总结

分页这件事,其实并没有绝对的“最佳方案”,每种方式都有其适用的场景。具体到实际应用时,我们需要根据数据量的大小、用户的需求、查询的复杂度等多方面因素来选择。
  • 如果数据量不大,且查询相对简单,那么Limit Offset分页完全可以应付。
  • 对于大数据量的场景,Limit + 主键Id过滤是一个更合适的选择。
  • 如果你要实现“滚动加载”的体验,HasMore滚动查询肯定是最好的解决方案。
  • 如果你是在做复杂的搜索和检索工作,ElasticSearch分页查询的高效和强大功能不容忽视。
所以,选择合适的分页方式,关键在于根据业务的实际需求来做权衡,搞清楚自己要做什么,再来选对工具,才是最靠谱的做法!
对编程、职场感兴趣的同学,可以链接我,微信:462135539 拉你进入“程序员交流群”。
🔥东哥私藏精品 热门推荐🔥

东哥作为一名超级老码农,整理了全网最全《Java高级架构师资料合集》
资料包含了《IDEA视频教程》《最全Java面试题库》、最全项目实战源码及视频》及《毕业设计系统源码》总量高达 650GB 。全部免费领取!全面满足各个阶段程序员的学习需求。

Java面试那些事儿
回复 java ,领取Java面试题。分享AI编程,Java教程,Java面试辅导,Java编程视频,Java下载,Java技术栈,AI工具,Java开源项目,Java简历模板,Java招聘,Java实战,Java面试经验,IDEA教程。
 最新文章