热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何优化大表分页查询的Limit性能问题?

关注“Java艺术”一起来充电吧!完成需求,不只在于速度,更要考虑质量。在规定的时间内完成需求的情况下,如果还有时间,应当想一下还能怎么优化,从性能、代码可读性、可扩展性层面考虑。

《如何优化大表分页查询的Limit性能问题?》

关注“Java艺术”一起来充电吧!

完成需求,不只在于速度,更要考虑质量。在规定的时间内完成需求的情况下,如果还有时间,应当想一下还能怎么优化,从性能、代码可读性、可扩展性层面考虑。进步就是这样一点点积累的。

昨天写的那篇有点小失误,在此修正一下。其实mybatis-plus提供的优化器做得非常好,它不仅仅只是在优化后的sql之上加一层select count(1) from (原sql ) as total,而是直接优化为select count(1) from... where...,优化后的查询总数的sql性能更优。

但是limit的问题,mybatis-plus优化器是解决不的。如果表的数据量非常大,我们除了优化查询总数的sql之外,还是需要优化limit的。

我看到过很多文章介绍说通过id优化提升limit性能,他们所举的例子都是单表查询。之所以能只查单表,是因为表的设计上已经通过冗余字段去掉多表连接查询了,这也是值得推荐且主流的优化大表查询性能的做法。

通过在设计表的时候加上冗余字段,去掉多表链接查询,使用id优化提升limit性能的例子如下:

SELECT a.字段
FROM table a
RIGHT JOIN
(
SELECT id -- 只查id列
FROM table
WHERE .....(非聚簇索引的条件查询)
LIMIT 1000000,20
) as b ON b.id = a.id

SQL是:

SELECT 需要获取的字段
FROM table
WHERE .....(非聚簇索引的条件查询)
LIMIT 1000000,20

由于非聚簇索引的叶子节点上面存储的是主键的id,因此,如果select只查主键,那么就不需要根据主键id再到聚簇索引上面获取记录信息,而如果select需要查询除主键外的其它字段信息,就必须要到聚簇索引上面取记录信息。

limit是在查询结果基础上跳过多少条记录,也就是说,跳过多少条记录也是需要查询这些记录的信息的。如limit 10000,20,那么就需要10020次根据主键id到聚簇索引上面取记录信息,而select id就能减少这10020次查询,因为非聚簇索引上面存的就是主键id。前提是where后面的条件必须确保都是走索引,在全表扫描下,任何优化都是徒劳。

根据这个思路,我优化了下最近做的一个需求的分页查询。虽然是需要多表连接查询,但where部分条件是在主表上面筛选的,或者是通过优化手段,转为只在主表上面进行条件筛选的,因此也适合使用这种通过id优化limit性能的方案。

改造就是将原来的sql拆分为两部分。第一部分是去掉select选项,只保留ID,然后去掉多表连接。第一部分主要就是保留where后面的条件查询。根据条件查询,获取当前分页的记录的主键id。在这一部完成分页。

先根据筛选条件完成分页查询获取当前页的id

select `ID` from 主表 where 查询条件 LIMIT 90,10

分页还是通过mybatis-plus的分页插件完成。在查询IDmapper方法上完成分页,获取总数信息。下面是myatis-plus分页插件优化后的查询总数的sql

-- myatis-plus分页插件打印的sql
SELECT COUNT(1) FROM 主表 WHERE 查询条件

第二部分再是根据获取到的当前页的记录id去查询需要的字段。包括子查询、连接查询等。是原sql去掉where条件查询之后,替换为ID in ()的查询语句。

select 字段、子查询 from 主表、连接表 where 主表.ID in (上一次查询获取到的id)

这样优化之后,分页的性能就能提升了。

还有一些文章是介绍说通过id多优化的,如:

..... where id>=(page * pageSize) limit pageSize;

我认为这种方案是不实用的,即使表的记录的id是连续的,且中间没有记录被删除,但是根据条件筛选出来的记录的id也是连续的吗?这种方案实现的分页查询结果一定是不准确的。

如果是遇到多表连接查询,且查询条件也需要根据Join的表的某个字段做过滤的情况下,如何优化分页查询limit带来的性能开销?

select a.*,b.* from a left join b on a.b_id=b.id where a.xx=? and b.xx=?

这真的不是一个好的表结构设计,实在想不出好的优化方案。

我想到的一种是,因为分页查询点击下一页时,要求查询条件是不能变的,且正常情况下也是不会变的,如果变了页码就应该重新从1开始,可以使用内存缓存上一次查询的最大的id,根据用户+接口的维度去缓存,在获取下一页时,跳过上一次查询的最大id,然后取多少条记录就行了。但是缺点就是不能跳页查询,前端只能是下一页、下一页,而且还需要浪费内存去缓存查询状态,在查询条件发生变化的情况下,还需要清掉缓存。

关于分页limit的问题,你们项目中是如何解决的呢?欢迎留言讨论。

在此毫无违和感的向大家推荐一本书,建议买电子版的,我买的一些纸质的书都很少看,电子书的好处是随时随地都可以看,包括在地铁上、公交车上、躺在被窝里睡不着时。

《如何优化大表分页查询的Limit性能问题?》

《如何优化大表分页查询的Limit性能问题?》

公众号:Java艺术

扫码关注最新动态


推荐阅读
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了在SQL中查询分组后每组行数的统计方法。通过使用count()函数和GROUP BY子句可以统计每组的行数,但是如何统计所有组的行数呢?本文提供了一种实现方法,并给出了相应的SQL查询语句。 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • JavaScript设计模式之策略模式(Strategy Pattern)的优势及应用
    本文介绍了JavaScript设计模式之策略模式(Strategy Pattern)的定义和优势,策略模式可以避免代码中的多重判断条件,体现了开放-封闭原则。同时,策略模式的应用可以使系统的算法重复利用,避免复制粘贴。然而,策略模式也会增加策略类的数量,违反最少知识原则,需要了解各种策略类才能更好地应用于业务中。本文还以员工年终奖的计算为例,说明了策略模式的应用场景和实现方式。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • MySQL外键1对多问题的解决方法及实例
    本文介绍了解决MySQL外键1对多问题的方法,通过准备数据、创建表和设置外键关联等步骤,实现了用户分组和插入数据的功能。详细介绍了数据准备的过程和外键关联的设置,以及插入数据的示例。 ... [详细]
author-avatar
全拼wangziyiva_632
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有