如何优雅地实现分页查询

分页查询的优雅实现:不同数据库的LIMIT/OFFSET替代方案 在现代的数据库开发中,分页查询是常见的需求之一,尤其是当查询的数据量非常大的时候,如何高效地实现分页查询成为了数据库性能优化的一个重要课题。传统的LIMIT和OFFSET分页方案虽然简单易懂,但在数据量巨大时,往往会面临性能瓶颈,尤其是在偏移量(OFFSET)很大的情况下。本文将探讨如何在不同的数据库中,避免使用传统的,并通过优雅的替代方案提高分页查询的性能。无论是 MySQL、PostgreSQL,还是 SQL Server,我们都将提供相应的解决方案,帮助开发者在实际场景中提升分页查询的效率。传统的。 阅读详情
13467292-c86f450d3fb39b61

分页功能是很常见的功能,特别是当数据量越来越大的时候,分页查询是必不可少的。实现分页功能有很多种方式,如果使用的ORM框架是mybatis的话,有开源的分页插件可以使用,如:Mybatis-PageHelper。如果不使用分页插件,那么就需要手动分页了,由于不同的数据库实现分页的SQL语句并不一致,如Mysql使用的是limit关键字,而Oracle使用的是rownum,所以本文本文讲解的分页方案只适用于Mysql数据库。

基于limit的分页方案

首先讲讲分页操作必须满足的几个要求:一个是有序性,一个是不重复。有序性可以看成是不重复的前提条件,因为假如数据是无序的,那么就不能保证多个分页之间是不重复的。因此分页操作往往需要先对数据进行排序,然后再加上分页条件。我们讲的第一种方案是基于limit的分页方案,也是很多分页插件使用的分页方案。我们先来看看我们的测试数据。

先看一下表结构:

mysql> desc user;

+-------+------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-------+------------+------+-----+---------+-------+

| id | bigint(20) | NO | PRI | NULL | |

| name | char(50) | NO | | NULL | |

+-------+------------+------+-----+---------+-------+

2 rows in set

可以看到我们的user表只有2列,分别是bigint型的id和char型的name。

接下来看下表数据:

mysql> select count(*) from user;

+----------+

| count(*) |

+----------+

| 45116 |

+----------+

1 row in set

mysql> select * from user order by id asc limit 10;

+----+--------+

| id | name |

+----+--------+

| 0 | user_0 |

| 1 | user_1 |

| 2 | user_2 |

| 3 | user_3 |

| 4 | user_4 |

| 5 | user_5 |

| 6 | user_6 |

| 7 | user_7 |

| 8 | user_8 |

| 9 | user_9 |

+----+--------+

10 rows in set

可以看到数据总行数大概45000条。

基于limit实现分页是比较简单的:

mysql> select * from user order by id asc limit 10000,10;

+-------+------------+

| id | name |

+-------+------------+

| 10000 | user_10000 |

| 10001 | user_10001 |

| 10002 | user_10002 |

| 10003 | user_10003 |

| 10004 | user_10004 |

| 10005 | user_10005 |

| 10006 | user_10006 |

| 10007 | user_10007 |

| 10008 | user_10008 |

| 10009 | user_10009 |

+-------+------------+

10 rows in set

其中,limit后面的第一个参数表示下标,也就是从第10000行记录开始取,第二个参数表示总共取10行记录。

使用limit实现分页功能使用起来非常简单,但是有没有什么问题呢?

我们先来回顾一下前面说的分页需要满足的2个要素:有序性和不重复。上述的语句我们已经使用了order by 进行排序,所以是可以满足有序性的,但满足了不重复了吗?假设在查询当前页跟下一页之间插入了一条记录,且该数据的id小于当前页记录中最大的id,会怎么样呢?我们测试一下就知道了:

mysql> select * from user order by id asc limit 10000,10;

+-------+------------+

| id | name |

+-------+------------+

| 10000 | user_10000 |

| 10001 | user_10001 |

| 10002 | user_10002 |

| 10003 | user_10003 |

| 10004 | user_10004 |

| 10005 | user_10005 |

| 10006 | user_10006 |

| 10007 | user_10007 |

| 10008 | user_10008 |

| 10009 | user_10009 |

+-------+------------+

10 rows in set

mysql> insert into user(id,name) values(-1,'user_-1');

Query OK, 1 row affected

mysql> select * from user order by id asc limit 10010,10;

+-------+------------+

| id | name |

+-------+------------+

| 10009 | user_10009 |

| 10010 | user_10010 |

| 10011 | user_10011 |

| 10012 | user_10012 |

| 10013 | user_10013 |

| 10014 | user_10014 |

| 10015 | user_10015 |

| 10016 | user_10016 |

| 10017 | user_10017 |

| 10018 | user_10018 |

+-------+------------+

10 rows in set

可以看到,当我们在相邻的2页查询之间插入一条记录的时候,后面一页跟前面一页有记录重复了(id为10009的记录在相邻2页中都出现了)。原因在于插入一条记录之后,分页结构已经改变了,所以才会出现重复数据。

因此,使用limit进行分页似乎不是很优雅啊,接下来将介绍另外一种分页的写法。

基于limit与比较的分页方案

另外一种分页的写法可以这样考虑,比如我们要取的是从第10000行开始的10行记录,那么我们可以先把大于或等于10000行的数据查出来并排序,然后再取出前10行记录,这样也可以完成分页。接下来看具体的SQL语句:

mysql> select * from user where id >=10000 order by id asc limit 10;

+-------+------------+

| id | name |

+-------+------------+

| 10000 | user_10000 |

| 10001 | user_10001 |

| 10002 | user_10002 |

| 10003 | user_10003 |

| 10004 | user_10004 |

| 10005 | user_10005 |

| 10006 | user_10006 |

| 10007 | user_10007 |

| 10008 | user_10008 |

| 10009 | user_10009 |

+-------+------------+

10 rows in set

那么这种写法可以防止上面出现的问题吗?我们做个试验就知道了。

mysql> select * from user where id >=10000 order by id asc limit 10;

+-------+------------+

| id | name |

+-------+------------+

| 10000 | user_10000 |

| 10001 | user_10001 |

| 10002 | user_10002 |

| 10003 | user_10003 |

| 10004 | user_10004 |

| 10005 | user_10005 |

| 10006 | user_10006 |

| 10007 | user_10007 |

| 10008 | user_10008 |

| 10009 | user_10009 |

+-------+------------+

10 rows in set

mysql> insert into user(id,name) values(-4,'user_-4');

Query OK, 1 row affected

mysql> select * from user where id >=10010

order by id asc limit 10;

+-------+------------+

| id | name |

+-------+------------+

| 10010 | user_10010 |

| 10011 | user_10011 |

| 10012 | user_10012 |

| 10013 | user_10013 |

| 10014 | user_10014 |

| 10015 | user_10015 |

| 10016 | user_10016 |

| 10017 | user_10017 |

| 10018 | user_10018 |

| 10019 | user_10019 |

+-------+------------+

10 rows in set

可以看到,当在相邻的两页查询之间插入数据时,分页查询结果不会出现重复。其实也很好理解,因为虽然插入记录后,分页的结构变了,但是由于我们现在的分页查询是从固定的id开始查的,所以插入新的数据对后面的分页结果没有影响。

当然,这种分页查询也是有限制的。其只适用于用来排序的列具有唯一性的情况,在上述例子中,id列是主键,所以具有唯一性,故可以使用这种方式分页。如果用来排序的列不具有唯一性,比如说是时间戳,那么这种分页方式也可能出现重复,大家可以想想是为什么。

如果你现在在JAVA这条路上挣扎,也想在IT行业拿高薪,可以参加我们的训练营课程,选择最适合自己的课程学习,技术大牛亲授,8个月后,进入名企拿高薪。我们的课程内容有:Java工程化、高性能及分布式、高性能、高架构、性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点。如果你想拿高薪的,想学习的,想就业前景好的,想跟别人竞争能取得优势的,想进阿里面试但担心面试不过的,你都可以来,QQ群号为:835638062

分库分表后,如何优雅实现高效分页查询?5大方法对比揭秘 分库分表后的高效分页查询方案 分库分表后,传统分页查询面临数据分布不均、全局排序困难等问题。本文探讨五种解决方案: 全局查询法:简单但性能低,需合并排序所有分库数据; 禁止跳页法:仅支持逐页查询,避免深度分页,适合移动端; 精度损失法:牺牲数据精度减少查询量,适用非高精度场景; 二次查询法:首次粗查定位,二次精查数据,平衡性能与准确性; 中间表法:通过索引表快速定位目标数据,适合高频分页场景。 选择方案需结合业务需求(如数据精度)、系统架构及技术栈(如ShardingSphere或Django优化)。合理设 阅读详情

相关推荐

单细胞测序流程(十)KEGG通路富集分析与可视化圈图实战解析

本文详细解析了单细胞测序数据分析中KEGG通路富集分析与可视化圈图的完整实战流程。从差异表达基因列表出发,通过R语言进行KEGG富集分析,并利用Perl脚本进行基因ID转换,最终使用GOplot包绘制高级可视化圈图,帮助研究者将基因列表转化为有意义的生物学故事。

i7j8k9l的博客 408

优雅的分页/不分页两种情况查询(1.6)

这个接口是我之前写的,内部会模糊查、全查,然后把结果数据以分页查和非分页六种情况返回,但之前写的还是不够精简,如果不分页的话会查两次,所以这里改了一下。 逻辑是:前面直接使用buildPage()创建了分页结构,后面校验,如果分页参数size传0,即不需要分页时就直接把上面buildPage()的分页结构拿过来赋值, 把Records给set上值返回即可;否则就是需要分页,调selectPage方法,把分页参数page丢进去执行,即可返回,但是selectPage这个方法不但会处理page进行分页查了进行

SSHLY3的博客 1384

手把手教你用C++和NI-VISA写个简易仪器上位机(附QT工程配置)

本文详细介绍了如何使用C++和QT框架结合NI-VISA驱动开发跨平台仪器控制上位机软件。从Ubuntu环境配置、VISA通信核心架构设计到QT界面与业务逻辑解耦,提供了完整的实战指南和代码示例,帮助开发者快速构建专业级仪器控制程序。

weixin_42522374的博客 277

SpringBoot优雅的实现分页功能及原理简析

前言 分页功能是我们开发过程中常见的一个小功能,如何快速高效的实现一个分页功能呢。本文将带领大家快速搭建一个分页功能。 引入依赖 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> &lt

Aldeo 3970

逆向分析第一步:如何从HEX文件‘还原’出单片机的原始程序与数据?

本文详细解析了如何从HEX文件逆向分析出单片机的原始程序与数据,涵盖了固件逆向的底层逻辑与实践。通过介绍HEX文件的结构、内存映像重建技术以及专业工具链的使用,帮助读者掌握从十六进制数据到可执行代码的完整流程,适用于嵌入式系统开发和逆向工程领域。

weixin_29745609的博客 317

深入解析uncompyle6反编译pyc文件及常见错误修复指南

本文深入解析了使用uncompyle6工具反编译Python字节码文件(.pyc)的完整流程。针对实践中最高频的KeyError和Python版本范围限制两大错误,提供了详细的修复方案与步骤指南,并分享了处理复杂反编译结果的高级技巧与安全实践,是进行代码恢复、调试与分析的重要参考。

uber9的博客 536

如何优雅的写一个分页代码(三)

此分页的步骤完全是按照:见我的博客http://blog.youkuaiyun.com/u014010769/article/details/45720723,这个图的步骤来写分页的 1.写PageBean类,见我的博客http://blog.youkuaiyun.com/u014010769/article/details/45721753 2.写Action类,将jsp中需要的类放到指定的作用域中,这里我放到了值

李卫康的博客 1848

RK3568下MIPI屏幕调试技巧

通过合理配置设备树节点、精确计算像素时钟并完成编译烧录,可高效实现RK3568平台MIPI屏幕的点亮与显示调试。关键在于严格遵循屏幕规格书参数,结合内核日志定位问题,逐步优化时序配置。掌握这一流程后,开发者可快速适配不同分辨率、刷新率的MIPI屏幕,为嵌入式系统显示模块开发奠定基础。如果在调试中遇到特定问题(如驱动匹配失败、时钟计算误差),建议优先查阅屏幕规格书和RK3568芯片手册,或通过内核社区(如Linux-DRI邮件列表)获取支持。

文石_2009的博客 1206

java查询分页插件_如何优雅地实现分页查询

分页功能是很常见的功能,特别是当数据量越来越大的时候,分页查询是必不可少的。实现分页功能有很多种方式,如果使用的ORM框架是mybatis的话,有开源的分页插件可以使用,如:Mybatis-PageHelper。如果不使用分页插件,那么就需要手动分页了,由于不同的数据库实现分页的SQL语句并不一致,如Mysql使用的是limit关键字,而Oracle使用的是rownum,所以本文本文讲解的分页方案...

weixin_36165049的博客 545

「UG/NX」Block UI 曲线收集器CurveCollector

曲线收集器块用于选择一条或多条曲线,包括通过选择意图连接的末端曲线链。曲线选择意图用于此块,但它不支持“交点处停止”、“跟随圆角”、“中间链”和“特征内链”等规则选项。

何曾参静谧的博客 1092

YOLOv8改进 | 融合篇,YOLOv8改进主干网络为MobileNetV4+CBAM注意机制+Powerful-IoU损失函数(2024 最新IOU),全网首发,实现极限涨点

本文将在 YOLOv8 主干中引入 MobileNetV4 轻量化骨干,同时,在检测头引入 CBAM机制注意力机制,并采用 Powerful-IoU 损失函数作为模型的损失函数,其中,MobileNetV4 通过引入通用反向瓶颈(UIB)搜索块和 Mobie MQA 注意力模块创新设计,实现了模型的轻量级化;同时,MobileNetV4 采用了优化的 NAS 策略,通过粗粒度和细粒度搜索相结合的方法,显著提高了搜索效率并改善了模型质量。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 3799

DBAPI如何优雅的实现分页查询功能

分页查询的时候,用户往往需要传入当前第几页pageNo和每页显示的条数pageSize参数,根据这两个参数,从数据库中查询出当前页的数据。表示从第31条记录开始,查询10条记录。

我的博客 698

【目录】全志F1C100S/F1C200S学习笔记

全志F1C100S/F1C200S学习笔记目录 全志F1C100S/F1C200S学习笔记(1)——基础简介及资料 全志F1C100S/F1C200S学习笔记(2)——TF卡分区及系统构建烧录 全志F1C100S/F1C200S学习笔记(3)——u-boot编译与烧录 全志F1C100S/F1C200S学习笔记(4)——u-boot传递环境变量参数 全志F1C100S/F1C200S学习笔记(5)——主线Linux编译 全志F1C100S/F1C200S学习笔记(6)——设备树添加节点 全志F1C100S/

丨晋丨 1万+

分库分表后,如何优雅的实现高效分页查询?

分库分表的一般做法一般会使用三种算法:哈希分库分表: 根据分库分表键算出一个哈希值,根据这个哈希值选择一个数据库。最常见的就是数字类型的字段作为分库分表键,然后取余。比如在订单表里,可以按照买家的ID除以8的余数进行分表范围分库分表: 将某个数据按照范围大小进行分段。比如说根据ID,[0,1000)在一张表,[1000,2000)在另外一张表。最常见的应该是按照日期进行分库分表,比如每个月一张表中...

方志朋的博客 1260

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

电商后台如何用MyBatis-Plus优雅实现分页查询

MyBatis-Plus的分页插件配置非常简单,只需要在配置类中注册一个分页拦截器即可。它不仅简化了代码编写,还提供了很好的扩展性,能够应对各种复杂的分页查询场景。这里采用了分页结果+条件组合作为缓存key的策略,并设置了合理的过期时间。下面分享我在实际项目中的完整实现方案。前端Vue3项目需要特定的分页数据结构,我们自定义了一个分页结果包装类,统一返回包含当前页码、每页大小、总记录数和数据列表的标准格式。MyBatis-Plus提供了强大的Wrapper条件构造器,可以非常方便地构建复杂查询条件。

RubyLion28的博客 383

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

分页查询实战:手把手教你用 PageHelper 实现优雅的分页功能!

无论你是刚接触 MyBatis 的小白,还是有一定经验的开发者,这篇文章都能为你答疑解惑!是一个基于 MyBatis 的分页插件,它通过拦截 MyBatis 的执行器(Executor)来实现分页功能。从它的起源到现代应用,再到具体的代码实现和最佳实践,每一个环节都进行了详细的讲解。的核心思想是通过拦截 MyBatis 的 SQL 执行过程,在 SQL 执行前后动态添加分页逻辑。的不断发展,分页查询的功能会越来越强大。通过页分查询,我们可以将数据分成若干个“页面”,每次只加载当前页面的数据。

Leaton的博客 3105

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Spring如何使用4行代码优雅的实现模糊查询,精确查询,分页查询功能。

为什么80%的码农都做不了架构师?>>> ...

weixin_34233421的博客 1240

Flask-MongoEngine分页实现:如何优雅处理大数据集的分页查询

在现代Web应用开发中,处理大数据集时,分页是提升用户体验和系统性能的关键技术。Flask-MongoEngine作为MongoDB与Flask框架的桥梁,提供了强大而简洁的分页功能,帮助开发者轻松实现高效的大数据集浏览体验。本文将详细介绍如何利用Flask-MongoEngine的分页机制,构建流畅的分页查询功能。 ## 为什么需要分页? 当应用需要展示大量数据时,一次性加载所有记录会导致页

gitblog_00278的博客 1041

如何优雅设计mybtis工具类及实现分页查询,动态SQL&mybatis+struts组合使用

MyBatis工具类&mybatis+struts2整合 前提:主要内容 Mybatis工具类 动态sql语句(if/foreach) mybatis实现分页 ResultSet结果集 mybatis+struts2+mybatis+jsp整合 解决Mybatis报错问题 一、MyBatisUtil工具类的封装 快捷键:catsVar:强转快捷键 借鉴jdbcUtil工具类的封装。 1.冗余问题 封装: 1、获取链接 class xxx{ //工具方法 获取sql

程序员小王的博客 792
上一篇: 分布式之redis精讲
下一篇: 如何优雅的设计和使用缓存?
普通网友
博客等级 码龄8年 55粉丝 197原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值