当前位置: 首页 > java >正文

【调优】log日志海量数据分表后查询速度调优

原始实现

使用pagehelper实现分页

      // 提取开始时间的年份和月份,拼装成表名List<String> timeBetween = getTimeBetween(condition);List<String> fullTableName = getFullTableName(Constants.LOG_TABLE_NAME, timeBetween);PageHelperUtil.startPage(condition);List<PulSysLogPageVo> list = logMapper.queryByPage(condition, fullTableName);return new PageSimpleInfo<>(list);

getTimeBetween 为从查询条件中把开始时间至结束时间取出

  private static List<String> getTimeBetween(PulSysLogCondition condition) {Timestamp startTime = condition.getStartTime();Timestamp endTime = condition.getEndTime();if (Objects.isNull(startTime)) {// 获取当前时间LocalDateTime currentTime = LocalDateTime.now();// 计算六个月前的时间LocalDateTime sixMonthsAgo = currentTime.minus(Period.ofMonths(6));// 将六个月前的时间转换为TimestampstartTime = Timestamp.valueOf(sixMonthsAgo);}if (Objects.isNull(endTime)) {endTime = new Timestamp(System.currentTimeMillis() + (24 * 60 * 60 * 1000L));}YearMonth startYearMonth = YearMonth.from(startTime.toLocalDateTime());// 提取结束时间的年份和月份YearMonth endYearMonth = YearMonth.from(endTime.toLocalDateTime());List<String> suffix = Lists.newArrayList();// 构建年份和月份的字符串格式,添加到列表中while (startYearMonth.isBefore(endYearMonth) || startYearMonth.equals(endYearMonth)) {String yearMonthString = String.format("%04d_%02d", startYearMonth.getYear(),startYearMonth.getMonthValue());suffix.add(yearMonthString);startYearMonth = startYearMonth.plusMonths(1);}return suffix;}

getFullTableName 是将时间拼接为表名

    private static List<String> getFullTableName(String tableName, List<String> suffixList) {List<String> fullTableNameList = Lists.newArrayList();// 构建年份和月份的字符串格式,添加到列表中for (String suffix : suffixList) {String logTableName = tableName + "_" + suffix;fullTableNameList.add(logTableName);}return fullTableNameList;}

queryByPage 使用mybtis查询

    SELECT  需要的字段FROM<foreach item="tableName" collection="tableNames" separator=" UNION ALL" open="(" close=") AS s" index="">SELECT 需要的字段FROM ${tableName}<where><if test="condition.startTime != null and condition.endTime != null">AND created_at &gt;= #{condition.startTime,jdbcType=TIMESTAMP}AND created_at &lt;= #{condition.endTime,jdbcType=TIMESTAMP}</if>其他条件</where></foreach>

优化后

  // 提取开始时间的年份和月份,拼装成表名List<String> timeBetween = getTimeBetween(condition);List<String> fullTableName = getFullTableName(Constants.LOG_TABLE_NAME, timeBetween);List<PulSysLogPageVo> resultList = new ArrayList<>();int remaining = condition.getRows();long total = 0;Map<String, Integer> tableCountMap = new HashMap<>(fullTableName.size());// 按表优先级逐个查询for (String tableName : fullTableName) {if (remaining <= 0) {break;}// 单表查询int singleTotal = logMapper.selectSingleTableCount(condition, tableName);total += singleTotal;tableCountMap.put(tableName, singleTotal);}long previousTotal = 0;int globalStart = (condition.getPage() - 1) * condition.getRows();if (globalStart > total) {return new PageSimpleInfo<>();}for (String tableName : fullTableName) {int singleTotal = tableCountMap.get(tableName);if (singleTotal <= 0) {continue;}// 当前表之前的记录总数previousTotal += singleTotal;if (previousTotal <= globalStart) {continue;}// 当前表实际起始位置 =   全局起始 -当前表之前的记录总数 ;int localStart = Math.toIntExact(globalStart - (previousTotal - singleTotal));if (condition.getRows() > remaining) {localStart = 0;}// 当前表最多能取的数量int localSize = Math.min(remaining, singleTotal);// 在计算localSize后增加校验if (localSize <= 0) {continue; // 跳过该表查询}List<PulSysLogPageVo> list = logMapper.querySingleTable(condition,tableName,localStart,localSize);resultList.addAll(list);int actualFetched = list.size();remaining -= actualFetched;if (remaining <= 0) {break;}}PageSimpleInfo<PulSysLogPageVo> pageInfo = new PageSimpleInfo<>(resultList);pageInfo.setTotal(total);return pageInfo;

selectSingleTableCount 获取每个表的数据量

        SELECT COUNT(1) FROM ${tableName}<where><if test="condition.startTime != null and condition.endTime != null">AND created_at &gt;= #{condition.startTime,jdbcType=TIMESTAMP}AND created_at &lt;= #{condition.endTime,jdbcType=TIMESTAMP}</if>
其他查询条件</where>

querySingleTable 查询单表

 SELECT需要的字段FROM ${tableName} s<where><if test="condition.startTime != null and condition.endTime != null">AND created_at &gt;= #{condition.startTime,jdbcType=TIMESTAMP}AND created_at &lt;= #{condition.endTime,jdbcType=TIMESTAMP}</if>其他查询条件</where>ORDER BY created_at DESCLIMIT #{offset}, #{pageSize}

经过测试

原始查询单表百万级,查询半年记录也就是6个表,12s+
优化后查询单表百万级,查询半年记录也就是6个表,100ms+

http://www.xdnf.cn/news/1424.html

相关文章:

  • 语法长难句
  • 破茧成蝶:阿里云应用服务器让传统 J2EE 应用无缝升级 AI 原生时代
  • 汽车可变转向比系统的全面认识
  • Python3(7) 数字类型
  • 穿越链路的旅程:深入理解计算机网络中的数据链路层
  • OpenVINO教程(五):实现YOLOv11+OpenVINO实时视频目标检测
  • Qt实战之将自定义插件(minGW)显示到Qt Creator列表的方法
  • Stable Baselines3 结合 gym 训练 CartPole 倒立摆
  • 【C++】vector扩容缩容
  • 2025/4/23 心得
  • 视频图片去水印处理图像 HitPaw Watermark Remover 软件工具WIN
  • MacOS中安装Python(homebrew,pyenv)
  • Java实现插入排序算法
  • 杭电oj(1087、1203、1003)题解
  • 云原生--CNCF-3-核心工具介绍(容器和编排、服务网格和通信、监控和日志、运行时和资源管理,安全和存储、CI/CD等)
  • gtest、gmock的使用
  • Google搜索技巧
  • 【官方正版,永久免费】Adobe Camera Raw 17.2 win/Mac版本 配合Adobe22-25系列软
  • 若依项目部署小结
  • OSPF的优化
  • 进程(Process)详解
  • 【自然语言处理与大模型】大模型参数规模与部署配置调查2025第一季度
  • LSA六种类型
  • VScode
  • 5.3 分布式事务
  • git lfs下载大文件限额
  • 查询Hologres或postgresql中的数据
  • php基础
  • 算法训练营第一天|704.二分查找、27.移除元素、977.有序数组的平方
  • 集结号海螺捕鱼组件搭建教程与源码结构详解(第四篇)