返回顶部
首页 > 资讯 > 数据库 >深度翻页导出导致慢SQL,mysqlCPU飙升优化方案
  • 893
分享到

深度翻页导出导致慢SQL,mysqlCPU飙升优化方案

sql数据库 2023-09-18 10:09:28 893人浏览 独家记忆
摘要

慢sql原因分析: 深度翻页 多表JOIN 大IN id倒排序 本文针对深度翻页的优化进行探讨 方案1:  将limit   offset, pageSize的方式改成 id > xx limit pageSize. 这样能走Id

sql原因分析:

深度翻页

多表JOIN

大IN

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范围查询

selectmin(b.id) as minId, max(b.id) as maxId, count(1) as countfrom storage_batchnum b

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;@Getter@Setter@ToString@AllArgsConstructorpublic class ExportIdRangeDTO implements Serializable {        private int minId = 0;        private int maxId = 0;        private long count = 0;    public boolean isValid() {        return minId > 0 && maxId > 0;    }        public List splitByPageCount(int pageCount) {        List splitList = new ArrayList();        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());    }}
   and b.id >= #{minId} and b.id <= #{maxId}

按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 idRangeList = idRangeRes.splitByPageCount(pageCnt);                    AtomicInteger pageNum = new AtomicInteger(0);                    for (ExportIdRangeDTO idRange : idRangeList) {                        int pn = pageNum.incrementAndGet();                        Map 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 list = exportMap.get(i).get().getList();                        ExportexcelUtil.insertDataToExcel(work, colName, list, line, true);                        line = line + list.size();                    }                }            } 

来源地址:https://blog.csdn.net/Jinliang_890905/article/details/132668549

您可能感兴趣的文档:

--结束END--

本文标题: 深度翻页导出导致慢SQL,mysqlCPU飙升优化方案

本文链接: https://lsjlt.com/news/411595.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作