分页查询的几种不同方式

mysql分页查询的几种方式

注:大写单词为mysql关键字,小写单词为参数

sql语句适用场景缺点
方式一SELECT * FROM tableName LIMIT #{offset},#{size}数据库中数据不多时的分页查询当使用LIMIT offset,size命令时,mysql会逐条遍历,抛弃前offset条数据,然后取size条数据,当offset非常大时性能下降明显
方式二SELECT * FROM table WHERE id > #{id} LIMIT #{size}需要连续取值时的分页查询当要跨页查询时(例如当前是第1页,直接跳到第5页的数据),尤其是现在普遍使用雪花算法生成id,无法得知id的具体值
方式三SELECT * FROM table WHERE id > #{id} ORDER BY id LIMIT #{offset},#{size}数据不多且不连续查询方式一和方式二结合,虽然解决了方式二的问题,当跨页查询的跨度太大时(例如从第5页跳转到第1000页),仍然会有方式一的问题
方式四SELECT * FROM table AS a INNER JOIN(SELECT id FROM table ORDER BY id LIMIT #{offset},#{size}) AS b USING(id)优化方式一当offset很大时同样有性能问题
方式五SELECT * FROM table WHERE id >(SELECT id FROM table ORDER BY id limit #{offset},1) LIMIT #{size}优化方式四相较于方式4不需要进行内联操作,但仍有同样的问题存在

基于缓存实现分页查询

问题关键点:基于以上的几种sql语句分析,分页查询的性能问题主要出现在当offset很大时,mysql需要逐条查询后丢弃数据,极端情况下几乎接近扫描全表,而不使用offset时(方式二)无法连续查询。

解决思路:使用方式二,找到一种快速定位id的方法即可解决扫描全表的问题

实现方案:(前提是使用自增且不重复的字段)

1、当向数据库新增或删除数据时,将数据的id维护到redis的zset集合中;

2、(可选)以数据的id为key,将整行数据存储到redis中

3、确定offset的值后,可以获取指定排名的数据id(zset使用跳表,查询的时间复杂度为O(logN)

4、确定id后使用方式二进行分页查询(或根据id在redis中查询数据)

问题:

1、保证数据库和缓存数据的一致性是另一个待研究的领域

2、很难实现复杂业务场景的分页查询,如指定筛选条件的分页查询

ORDER BY 和 LIMIT 关键字共用时所引发的数据问题
现象:
ORDER BY 和 LIMIT 关键字混用时,当ORDER BY的字段内容不唯一时,可能会导致分页查询的数据有重复。

根据官方文档的解释:
如果order by的字段有多个行都有相同的值,mysql是会随机的顺序返回查询结果的,具体依赖对应的执行计划。也就是说如果排序的列是无序的,那么排序的结果行的顺序也是不确定的。

解决方案:
在使用ORDER BY时,将主键作为排序值即可避免此问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 MyBatis 中,常见的分页查询方法有以下几种: 1. 使用 LIMIT 和 OFFSET 关键字进行分页 这是一种最常见的分页查询方法。在 SQL 语句中使用 LIMIT 和 OFFSET 关键字来限制查询结果的数量和起始位置,例如: ```sql SELECT * FROM table_name LIMIT start, pageSize; ``` 其中,start 表示查询结果的起始位置,pageSize 表示每页的记录数。在 MyBatis 中,可以使用占位符和参数的方式来动态生成 SQL 语句,例如: ```xml <select id="findUsers" parameterType="map" resultType="User"> select * from user <where> <if test="username != null and username != ''"> and username like #{username} </if> </where> order by id desc limit #{start}, #{pageSize} </select> ``` 2. 使用 RowBounds 进行分页 RowBounds 是 MyBatis 提供的一个用于分页查询的类,它可以在查询语句中指定起始位置和查询数量,例如: ```java List<User> users = sqlSession.selectList("findUsers", null, new RowBounds(start, pageSize)); ``` 这种方法需要在查询语句中不使用 LIMIT 和 OFFSET 关键字,而是在查询方法中使用 RowBounds 来指定分页参数。 3. 使用 MyBatis 分页插件进行分页 MyBatis 提供了一些分页插件,例如 PageHelper、Mybatis-Plus 等,它们可以方便地实现分页查询功能,只需要在项目中引入对应的依赖即可。使用插件进行分页查询的示例代码如下: ```java PageHelper.startPage(pageNum, pageSize); List<User> users = userDao.findUsers(username); PageInfo<User> pageInfo = new PageInfo<>(users); return new Page<>(pageInfo.getTotal(), users); ``` 其中,PageHelper 是一个 MyBatis 分页插件,它封装了分页查询的逻辑,只需要调用 startPage() 方法来指定页码和每页的记录数,然后在查询方法返回后调用 PageInfo 类来获取分页查询结果。这种方法简单易用,不需要手动编写分页查询语句。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值