深度翻页导出导致慢SQL,mysqlCPU飙升优化方案
慢SQL原因分析:
1.深度翻页
2.多表JOIN
3. 大IN
4. id倒排序
本文针对深度翻页的优化进行探讨
方案1:
将limit offset, pageSize的方式改成 id > xx limit pageSize.
这样能走Id索引,提高速度。
缺点:不能使用多线程,入参ID从上页结果。
方案2:
基于 方案1再优化, 将limit offset, pageSize 的方式改成 id > startId and id< endId .
一次性查出符合条件的ID范围,然后切分ID范围进行查询。(可分实际ID划分,或逻辑范围划分)
优点: 能用多线程并发查询。
缺点:逻辑范围划分有的id范围可能无数据,进行无效查询。
方案3:
终极方案:设置fetchSize,思想是 一次查询在Mysql侧缓冲全量数据,程序侧通过游标cursor批量读取数据,通过回调函数resulthandler处理数据。
优点: 不用多次和Mysql查询,一次查询多次读取数据。回调里可以使用多线程操作数据。
缺点: Mysql要缓冲全量数据,内存飙升

方案二步骤:
(1) 查询 对应表的ID范围,COUNT条数
(2) 根据count条数,和每页数量,计算页数,根据页数 和 ID范围进行ID范围切分。
(3)根据ID范围,发起多线程并发查询。
其中具体核心逻辑代码:
ID范围查询
<!-- 统计分页查询总条数 --><select id="findIdRange" resultType="com.xyy.ms.export.core.erpreport.dto.ExportIdRangeDTO">selectmin(b.id) as minId, max(b.id) as maxId, count(1) as countfrom storage_batchnum b<include refid="batchNumExportWhere"></include></select>
ID切分逻辑:
package com.xyy.ms.export.core.erpreport.dto;import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;/*** @author stivenjin* @version 1.0* @description 说明: 取表中最小和最大ID, 用ID翻页查询,避免深度翻页(批号库存翻页导出)* 翻页优化步骤:* 1:根据ID范围,进行切分组* 2:用每组 的边界值进行id范围翻页查询。* @date 2023/9/1 18:10*/
@Getter
@Setter
@ToString
@AllArgsConstructor
public class ExportIdRangeDTO implements Serializable {/*** 最小ID*/private int minId = 0;/*** 最大ID*/private int maxId = 0;/*** 总条数*/private long count = 0;public boolean isValid() {return minId > 0 && maxId > 0;}/*** 按页数分隔ID范围* @param pageCount* @return*/public List<ExportIdRangeDTO> splitByPageCount(int pageCount) {List<ExportIdRangeDTO> splitList = new ArrayList<ExportIdRangeDTO>();int startId = minId;int endId = maxId;int pageSize = (int)Math.ceil((Double.valueOf(maxId) - Double.valueOf(minId)) / pageCount);System.out.println("pageSize:" + pageSize + ",pageCount:" + pageCount);int tmp = endId;for(int i = 1 ;i<=pageCount;i++){if(startId <= tmp){if(startId + pageSize <= tmp){endId = startId + pageSize ;}else{endId = tmp;}}else{break;}//System.out.println("循环调用:" + startId + " : " + endId);splitList.add(new ExportIdRangeDTO(startId, endId, 0));if(endId <= tmp){startId = endId +1;}}return splitList;}public static void main(String[] args) {ExportIdRangeDTO dto = new ExportIdRangeDTO(100,823540, 0);dto.splitByPageCount(10);System.out.println("切分一片原始:" + dto.getMinId() + " : " + dto.getMaxId());}
}
<if test="minId != null and maxId != null">and b.id >= #{minId} and b.id <= #{maxId}
</if>
按ID范围切分后,可用多线程并发查询导出
taskExecutor.submit
// 增加顺序按起点ID导出模式,避免深度翻页慢SQL(之前是多线程并发深度翻页查MYSQL,mysql cpu飙升)if (batchNumExportUseId) {ExportIdRangeDTO idRangeRes = exportStorageBatchNumApi.findIdRange(params);logger.info(" taskId [{}] 开始-异步顺序导出,idRange={}",taskId, JSON.toJSONString(idRangeRes));if (idRangeRes != null && idRangeRes.isValid()) {paramsObject.put("pageSize", StorageWebConstant.PURCHASE_CALL_PAGESIZE);int pageCnt = (int)(idRangeRes.getCount()/StorageWebConstant.PURCHASE_CALL_PAGESIZE);pageCnt = pageCnt + (idRangeRes.getCount()%StorageWebConstant.PURCHASE_CALL_PAGESIZE == 0 ? 0:1);List<ExportIdRangeDTO> idRangeList = idRangeRes.splitByPageCount(pageCnt);AtomicInteger pageNum = new AtomicInteger(0);for (ExportIdRangeDTO idRange : idRangeList) {int pn = pageNum.incrementAndGet();Map<String, Object> exportParamMap = new HashMap<>();exportParamMap.putAll(paramsObject);exportParamMap.put("pageNum", pn);exportParamMap.put("minId", idRange.getMinId());exportParamMap.put("maxId", idRange.getMaxId());logger.info("## taskId [" + taskId + "]开始导出,第 " + pn + " 页 {}-{}", idRange.getMaxId(), idRange.getMaxId());exportMap.putIfAbsent(pn, taskExecutor.submit(() -> storageReportService.listStorageBatchNumReportView(exportParamMap)));}for (int i = 1; i <= pageNum.get(); i++) {List<StorageReportViewVo> list = exportMap.get(i).get().getList();ExportExcelUtil.insertDataToExcel(work, colName, list, line, true);line = line + list.size();}}}
相关文章:
深度翻页导出导致慢SQL,mysqlCPU飙升优化方案
慢SQL原因分析: 1.深度翻页 2.多表JOIN 3. 大IN 4. id倒排序 本文针对深度翻页的优化进行探讨 方案1: 将limit offset, pageSize的方式改成 id > xx limit pageSize. 这样能走Id索引,提高速度。 缺点:不能使用多线程…...
小谈设计模式(1)—总序
小谈设计模式(1)—总序 开始操作设计模式总论设计模式是什么组成要素模式名称问题描述解决方案效果描述 设计模式有什么作用提供可重用的解决方案提高代码的可读性和可维护性促进代码的可扩展性提高代码的灵活性和可重用性促进团队合作和沟通作用总结 为…...
【c++】stringstream基础:实现数据类型转换和字符串分割
传统实现整型转换为字符串需要使用itoa或者sprintf,对于itoa和atoi的使用可以看文章: atoi和itoa极简无废话概述 但是用这两个函数进行转换时,所需要的空间事先不确定,所以可能造成程序崩溃,今天介绍的stringstream可…...
Java基础学习笔记-5
前言 Java编程语言是一门广泛应用于软件开发领域的高级编程语言。它的强大特性和跨平台性使其成为许多开发者的首选语言。本文将介绍一些Java编程的关键概念,包括函数重载、可变参数、值传递、递归等,这些概念是Java编程的基础,对于理解和掌…...
合同交付类项目如何高效管理?
美国项目管理协会(PMI)保罗格蕾斯曾说:“当今社会,一切都是项目,一切也将成为项目。”在“万事皆项目”的背景下,企业在运营过程中会产生大量的项目型业务活动,例如:举办市场活动、产品研发、进行企业内训、采购招标、工程建设等等。那么按照…...
两性养生网站源码 生活类减肥网站源码 健康网模板源码 支持QQ登录和百度主动推送
本套模板非常适合生活类,两性类,减肥类等等类型的网站,这类型网站比较好做流量,因为客户群体众多, 可以自行改内容为其他类型网站模板总体非常简洁漂亮,配色合理,视觉舒服,并且配合…...
CentOS7安装Jenkins(更改默认运行的端口号8080->16060)
第一步: 端口号为默认8080 的安装是:Jenkins安装配置 第二步:将默认运行端口8080—>16060 首先修改配置文件 修改配置文件:vi /etc/sysconfig/jenkins修改内容:# 服务监听端口JENKINS_PORT"16060"然后…...
Java开发之Mysql【面试篇 完结版】
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、知识体系二、Mysql-优化1. 优化-如何定位慢查询① 问题引入② 解决方案③ 问题总结④ 实战面试 2. 优化-sql执行很慢,如何解决① 问题引入② 解…...
【实战】十二、自动化测试 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十九)
文章目录 一、项目起航:项目初始化与配置二、React 与 Hook 应用:实现项目列表三、TS 应用:JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…...
【人月神话】重新探索人月神话:软件工程的现实与挑战
人月神话是一篇由美国软件工程师弗雷德里克布鲁克斯所写的软件工程经典之作,最早发表于1975年。这篇文章的全名是《人月神话:软件工程的神话与现实》(The Mythical Man-Month: Essays on Software Engineering),它涵盖…...
电阻和电容
目录 1、常见的电阻器 2、电容 编辑 1、常见的电阻器 对于电阻需要了解三个参数(查询电阻的数据手册): 1、封装:就是电阻的尺寸或者大小,看焊在你的pcb板上是否合适。 2、标称:电阻的电阻大小、精度、…...
01-Java-日志框架
1 日志技术概述 1.1 什么是日志技术 日志技术是一种记录和存储应用程序运行时信息的技术。它可以捕获应用程序的状态、事件、错误和警告等信息,并将其保存到日志文件或其他存储介质中。日志技术可以帮助开发人员和运维团队了解应用程序的运行情况,进…...
【js】map、filter、reduce、fill(待补充...)
const arr [{ id: 1, flag: true },{ id: 2, flag: true },{ id: 3, flag: false },{ id: 4, flag: true }, ]map:返回的是对每个元素进行操作后的结果数组,这个数组的长度和原数组相同 const result arr.map((item: any) > {return item.flag fa…...
【JPC出版】第二届能源与电力系统国际学术会议 (ICEEPS 2023)
第二届能源与电力系统国际学术会议 (ICEEPS 2023) 2023 2nd International Conference on Energy and Electrical Power Systems 第二届能源与电力系统国际学术会议 (ICEEPS 2023)将于2023年10月27日至29日在中国厦门举行。ICEEPS 将汇集能源科学、电气工程和电力系统领域的…...
51单片机的简易篮球计分器倒计时仿真设计( proteus仿真+程序+原理图+报告+讲解视频)
51单片机的简易篮球计分器倒计时仿真设计( proteus仿真程序原理图报告讲解视频) 1.主要功能:2.仿真3. 程序代码4. 原理图5. 设计报告6. 设计资料内容清单&&下载链接 51单片机的简易篮球计分器倒计时仿真设计( proteus仿真程序原理图报告讲解视频…...
医院安全不良事件报告系统源码 PHP+ vue2+element+ laravel8+ mysql5.7+ vscode开发
不良事件上报系统通过 “事前的人员知识培训管理和制度落地促进”、“事中的事件上报和跟进处理”、 以及 “事后的原因分析和工作持续优化”,结合预存上百套已正在使用的模板,帮助医院从对护理事件、药品事件、医疗器械事件、医院感染事件、输血事件、意…...
Mybatis -- 读取 DATE 类型字段时可能遇到的问题(夏令时问题)
在使用 MYBATIS 读取数据库字段的时候,我们一般需要为查询字段指定数据类型。特别是当我们使用 mybatis generator 去生成对应的接口代码时,会自动按照数据库字段类型生成响应映射规则的代码。 如下,左侧是 date 类型生成的字段映射规则&…...
第10节-PhotoShop基础课程-选区工具
文章目录 前言1.矩形选区 shift 是正方形1.任意比例2.等比绘制 先点击再按shift3.中心绘制1.任意比例 先点击再按Alt2.等比绘制 先点击再按Alt Shift 4.移动选区 按住空格 2.椭圆选区1.椭圆选区2.正圆选区 shift键3.中心圆选区 Alt Shift 3.选取选项1. 选区1.建立选区2.加选 s…...
【C++】C++动态内存管理
🏳️🌈C/C内存分布 说明: 1.我们的代码并非放在代码段里的,而是以文件的形式存在磁盘上的。 代码经过编译链接形成的二进制指令,才是放进代码段里的。(即可执行代码) 2.“abcd”如果没有被c…...
Java中使用JTS实现WKT字符串读取转换线、查找LineString的list中距离最近的线、LineString做缓冲区扩展并计算点在缓冲区内的方位角
场景 Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等): Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)_jts-core_霸道流氓气质的博客-CSDN博客 JavaGeoTools实现WKT数据根据EPSG编码进行坐标系转换&…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
