文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

你真的很懂分页查询吗?

2024-11-30 00:05

关注
select * from transactions
order by created_at desc
limit  offset 100

解决这个问题的一种方法是使用键集分页;如果行集是在一个唯一列上排序的,我们可以使用该列的值来定位分页,而不是基于偏移量定位分页。只要在行集上有一个可排序的索引列,给定一个列值,我们可以在常量时间内访问到相应的分页。

我们确实会由此失去跳转到第 p 页的能力,但对于大多数应用程序来说,这不是一个问题。

键集分页

键集分页的工作原理是,通过对感兴趣的列和唯一列进行排序,来生成对表的结果集的总排序。在 PostgreSQL 中,order by语句是不稳定的,这意味着我们需要保证结果集的总排序,以确保用户看到稳定的顺序。我们通过在所有order by语句中包含一个唯一列作为最低优先级列,来实现这一点。在这里,主键是一个很好的选择。

要获取一个分页的结果,我们可以这样做:

select * from transactions
    where created_at, id >= '', ''
order by created_at, id
limit 

那么新的问题来了,应该如何获得下一页和上一页的游标(以便服务于 UI 上的前进和后退按钮)?还有如何实现多列排序?

有几点需要考虑:

能否快速检索到当前页面、下一页的游标位置和上一页的游标位置?并且所有这些都应在一个查询中完成。

是否可以轻松地扩展查询,以支持任意排序和筛选?

基本思想是在一个 CTE 表达式中获取当前页面和游标(它们在行集中相邻),在另一个 CTE 表达式中获取前一页的游标,合并结果,相应地标记它们(previous_cursor,current_page,next_cursor)并返回它们,所有这些都是作为一个完整查询的一部分。

第一步是过滤表中的数据。我们不用物化filtered_rows表达式,这会强制表达式与依赖查询合并(请参阅文档,以了解更多信息)。在这样做的过程中,我们需要付出为每个依赖查询重新计算filtered_rows查询的额外成本,但由此获得了利用表上索引的能力。这大大加快了后面的操作。

为了获取游标,我们查询id列以及排序中涉及的任何列。在这个例子中,我们在created_at上排序,但是如果需要的话,在多个列上排序也是很容易的。请注意,我们将id列作为低优先级列进行排序。

cursor as
    (select created_at, id from rows where id = ? order by created_at, id limit 1)

获取当前页面和下一页的游标是很简单的。关键要注意的是 WHERE 子句,它只选择在总排序中游标行之后的行,还有 ORDER 和 LIMIT 子句,它们联合检索紧接在游标之后的行,形成当前页面和下一页游标:

current_page_and_next_cursor as
    (select *
        from rows
    where (created_at, id) >= (select * from cursor)
    order by created_at, id
    limit 
)

获取前一页也同样简单。需要注意的主要事情是,WHERE 子句中相等条件的反转(因为我们想要选择游标之前的行)和order by子句的反转,以确保我们选择游标之前的 n 行(而不是结果集中的前 n 行)。当我们组合结果时,我们只要从集合中获取第一行,以得到前一页的游标。

previous_page as
    (select *
        from rows
    where (created_at, id) < (select * from cursor)
    order by created_at desc, id desc
    limit 
),

构建完相关 CTE 表达式后,最后一项任务是将结果行合并在一起并标记它们:

(select *, 'previous_cursor' as label from previous_page order by created_at, id limit 1)
union all
(select *, 'current_page' as label from current_page_and_next_cursor order by created_at, id limit )
union all
(select *, 'next_cursor' as label from current_page_and_next_cursor order by created_at, id limit 1 offset );

有几件事需要在这里提一下。首先,使用union all来保持结果集的顺序。第二点,再次使用 OFFSET 和 LIMIT 从 previous_page 和 current_page_and_next_cursor 的 CTE 表达式中选择单行,它们分别表示上一页游标和下一页游标。最后,添加一个标签,来标识与应用程序相关的行。如果前一页不存在(即当游标指向结果集中的第一行时)或下一页不存在(即当游标指向最后一页的 pageSize 大小窗口范围内的行时),则不返回游标。

总结

Limit-Offset 分页有两个大问题,结果不一致和偏移效率低下。一致性是指,遍历结果集的过程中,每个行应精准检索一次,而不会遗漏或重复。偏移效率低下是指将结果偏移较大时会产生的延迟。

键集分页速度很快,而且也是一致的。在当前页面之前插入/删除任何内容都不会影响结果。这种方法的两个缺点是,对随机访问支持不友好,以及客户端和服务器之间可能存在耦合。

来源:红石PG内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯