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

【调优】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+

相关文章:

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

原始实现 使用pagehelper实现分页 // 提取开始时间的年份和月份&#xff0c;拼装成表名List<String> timeBetween getTimeBetween(condition);List<String> fullTableName getFullTableName(Constants.LOG_TABLE_NAME, timeBetween);PageHelperUtil.startPage(c…...

hive默认的建表格式

在 Hive 中创建表时&#xff0c;默认的建表语法格式如下&#xff1a; CREATE TABLE table_name (column1_type,column2_type,... ) ROW FORMAT DELIMITED FIELDS TERMINATED BY , STORED AS TEXTFILE;在这个语法中&#xff1a; CREATE TABLE table_name&#xff1a;指定要创建…...

sass 变量

基本使用 如果分配给变量的值后面添加了 !default 标志 &#xff0c;这意味着该变量如果已经赋值&#xff0c;那么它不会被重新赋值&#xff0c;但是&#xff0c;如果它尚未赋值&#xff0c;那么它会被赋予新的给定值。 如果在此之前变量已经赋值&#xff0c;那就不使用默认值…...

微软Edge浏览器字体设置

前言 时间&#xff1a;2025年4月 自2025年4月起&#xff0c;微软Edge浏览器的默认字体被微软从微软雅黑替换成了Noto Sans&#xff0c;如下图。Noto Sans字体与微软雅黑风格差不多&#xff0c;但在4K以下分辨率的显示器上较微软雅黑更模糊&#xff0c;因此低分辨率的显示器建议…...

Vue生命周期详细解析

前言 Vue.js作为当前最流行的前端框架之一&#xff0c;其生命周期钩子函数是每个Vue开发者必须掌握的核心概念。本文将全面解析Vue的生命周期&#xff0c;帮助开发者更好地理解Vue实例的创建、更新和销毁过程。 一、Vue生命周期概述 Vue实例从创建到销毁的整个过程被称为Vue…...

基于c#,wpf,ef框架,sql server数据库,音乐播放器

详细视频: 【基于c#,wpf,ef框架,sql server数据库&#xff0c;音乐播放器。-哔哩哔哩】 https://b23.tv/ZqmOKJ5...

前端项目搭建集锦:vite、vue、react、antd、vant、ts、sass、eslint、prettier、浏览器扩展,开箱即用,附带项目搭建教程

前端项目搭建集锦&#xff1a;vite、vue、react、antd、vant、ts、sass、eslint、prettier、浏览器扩展&#xff0c;开箱即用&#xff0c;附带项目搭建教程 前言&#xff1a;一、Vue项目下载快速通道二、React项目下载快速通道三、BrowserPlugins项目下载快速通道四、项目搭建教…...

【C++游戏引擎开发】第21篇:基于物理渲染(PBR)——统计学解构材质与光影

引言 宏观现象:人眼观察到的材质表面特性(如金属的高光锐利、石膏的漫反射柔和),本质上是微观结构对光线的统计平均结果。 微观真相:任何看似平整的表面在放大后都呈现崎岖的微观几何。每个微表面(Microfacet)均为完美镜面,但大量微表面以不同朝向分布时,宏观上会表…...

什么是Maven

Maven的概念 Maven是一个一键式的自动化的构建工具。Maven 是 Apache 软件基金会组织维护的一款自动化构建工具&#xff0c;专注服务于Java 平台的项目构建和依赖管理。Maven 这个单词的本意是&#xff1a;专家&#xff0c;内行。Maven 是目前最流行的自动化构建工具&#xff0…...

强化学习复习,价值函数的推导——北大pdf p41(ppt75)(动手学也有)

我们经常看到强化学习中有求汇报期望 E E E&#xff0c;转化为价值函数(value function) V V V&#xff0c;策略的状态价值函数(State-Value function) V π V_π Vπ​和动作价值函数&#xff08;action-value function&#xff09; Q π Q_π Qπ​。还有提到通过将期望将消除…...

neo4j中节点内的名称显示不全解决办法(如何让label在节点上自动换行)

因为节点过多而且想让节点中所有文字都显示出来而放大节点尺寸 从neo4j中导出png,再转成PDF来查看时&#xff0c;要看清节点里面的文字就得放大5倍才行 在网上看了很多让里面文字换行的办法都不行 然后找到一个比较靠谱的办法是在要显示的标签内加换行符 但是我的节点上显示的是…...

day 32 学习笔记

文章目录 前言一、模版匹配的概念二、模版匹配方法 前言 通过今天的学习&#xff0c;我掌握了OpenCV中有关模版匹配和模版匹配方法的相关原理和操作 一、模版匹配的概念 模板匹配就是用模板图&#xff08;通常是一个小图&#xff09;在目标图像&#xff08;通常是一个比模板图…...

【GIT】github中的仓库如何删除?

你可以按照以下步骤删除 GitHub 上的仓库&#xff08;repository&#xff09;&#xff1a; &#x1f6a8; 注意事项&#xff1a; ❗️删除仓库是不可恢复的操作&#xff0c;所有代码、issue、pull request、release 等内容都会被永久删除。 &#x1f9ed; 删除 GitHub 仓库步骤…...

使用Python将YOLO的XML标注文件转换为TXT文件格式

使用Python将YOLO的XML标注文件转换为TXT文件格式&#xff0c;并划分数据集 import xml.etree.ElementTree as ET import os from os import listdir, getcwd from os.path import join import random from shutil import copyfile from PIL import Image# 只要改下面的CLASSE…...

docker容器监控自动恢复

关于实现对docker容器监控以及自动恢复&#xff0c;这里介绍两种实现方案。 方案1&#xff1a; 实现思路&#xff1a; 找到&#xff08;根据正则表达式&#xff09;所有待监控的docker容器&#xff0c;此处筛选逻辑根据docker运行状态找到已停止&#xff08;Exit&#xff09;类…...

【农气项目】基于适宜度的产量预报

直接上干货&#xff08;复制到开发工具即可运行的代码&#xff09; 1. 适宜度模型及作物適宜度计算方法 2. 产量分离 3. 基于适宜度计算产量预报 1. 适宜度模型及作物適宜度计算方法 // 三基点温度配置private final double tempMin;private final double tempOpt;private f…...

1、AI及LLM基础:Python语法入门教程

Python语法入门教程 ​ 这是一份全面的Python语法入门教程,涵盖了注释、变量类型与操作符、逻辑运算、list和字符串、变量与集合、控制流和迭代、模块、类、继承、进阶等内容,通过详细的代码示例和解释,帮助大家快速熟悉Python语法。 文章目录 Python语法入门教程一、注释二…...

3台CentOS虚拟机部署 StarRocks 1 FE+ 3 BE集群

背景&#xff1a;公司最近业务数据量上去了&#xff0c;需要做一个漏斗分析功能&#xff0c;实时性要求较高&#xff0c;mysql已经已经不在适用&#xff0c;做了个大数据技术栈选型调研后&#xff0c;决定使用StarRocks StarRocks官网&#xff1a;StarRocks | A High-Performa…...

服务器上安装node

1.安装 下载安装包 https://nodejs.org/en/download 解压安装包 将安装包上传到/opt/software目录下 cd /opt/software tar -xzvf node-v16.14.2-linux-x64.tar.gz 将解压的文件夹移动到安装目录(/opt/nodejs)下 mv /opt/software/node-v16.14.2-linux-x64 /opt/nodejs …...

精益数据分析(20/126):解析经典数据分析框架,助力创业增长

精益数据分析&#xff08;20/126&#xff09;&#xff1a;解析经典数据分析框架&#xff0c;助力创业增长 在创业和数据分析的学习道路上&#xff0c;每一次深入探索都可能为我们带来新的启发。今天&#xff0c;依旧带着和大家共同进步的想法&#xff0c;我们一起深入研读《精…...

9.策略模式:思考与解读

原文地址:策略模式&#xff1a;思考与解读 更多内容请关注&#xff1a;7.深入思考与解读设计模式 引言 你是否曾遇到过这样的情况&#xff1a;在一个系统中&#xff0c;有许多算法或策略&#xff0c;每种策略的实现逻辑相似&#xff0c;但在某些情况下需要进行替换和扩展&am…...

【HCIA】简易的两个VLAN分别使用DHCP分配IP

前言 之前我们通过 静态ip地址实现了Vlan间通信 &#xff0c;现在我们添加一个常用的DHCP功能。 文章目录 前言1. 配置交换机2. 接口模式3. 全局模式后记修改记录 1. 配置交换机 首先&#xff0c;使用DHCP&#xff0c;需要先启动DHCP服务&#xff1a; [Huawei]dhcp enable I…...

【设计模式-4】深入理解设计模式:工厂模式详解

在软件开发中&#xff0c;对象的创建是一个基础但至关重要的环节。随着系统复杂度的增加&#xff0c;直接使用new关键字实例化对象会带来诸多问题&#xff0c;如代码耦合度高、难以扩展和维护等。工厂模式&#xff08;Factory Pattern&#xff09;作为一种创建型设计模式&#…...

Spring Boot 整合 JavaFX 核心知识点详解

1. 架构设计与集成模式 1.1 Spring Boot 与 JavaFX 的分层架构设计 Spring Boot 与 JavaFX 的整合需要精心设计的分层架构,以充分利用两个框架的优势。 标准分层架构 ┌────────────────────────────────────────────────…...

Spring MVC DispatcherServlet 的作用是什么? 它在整个请求处理流程中扮演了什么角色?为什么它是核心?

DispatcherServlet 是 Spring MVC 框架的绝对核心和灵魂。它扮演着前端控制器&#xff08;Front Controller&#xff09;的角色&#xff0c;是所有进入 Spring MVC 应用程序的 HTTP 请求的统一入口点和中央调度枢纽。 一、 DispatcherServlet 的核心作用和职责&#xff1a; 请…...

亚马逊英国站FBA费用重构:轻小商品迎红利期,跨境卖家如何抢占先机?

一、政策背景&#xff1a;成本优化成平台与卖家共同诉求 2024年4月&#xff0c;亚马逊英国站&#xff08;Amazon.co.uk&#xff09;发布近三年来力度最大的FBA费用调整方案&#xff0c;标志着英国电商市场正式进入精细化成本管理时代。这一决策背后&#xff0c;是多重因素的叠…...

Redis在.NET平台中的各种应用场景

关键点总结 连接管理&#xff1a;所有示例都使用ConnectionMultiplexer来管理Redis连接&#xff0c;它是线程安全的&#xff0c;应该在整个应用程序中重用。 键设计&#xff1a;良好的键命名规范很重要&#xff0c;通常使用冒号分隔的层次结构(如page:home:pv)。 数据序列化&…...

近几年字节测开部分面试题整理

文章目录 前言一、面试问题1. 在浏览器url上写一个地址&#xff0c;请描述一下网络方面有哪些变化2. 堆栈数据存储位置3. HTTP POST请求支持的数据格式4. 缩容要注意些什么&#xff1f;5. Python中元组、数组、list和数组的区别6. Python中is和的区别7. HTTP与HTTPS8. 已知两个…...

艾蒙顿桌面app下载-Emotn UI下载安装-emotn ui官方tv版安卓固件

在智能电视桌面应用的领域里&#xff0c;Emotn UI 凭借其简洁无广告、可自定义等特点&#xff0c;赢得了不少用户的关注。然而&#xff0c;小编深入了解后发现了一款更好用的电视桌面——乐看家桌面在诸多方面更具优势&#xff0c;能为你带来更优质的大屏体验。 乐看家桌面内置…...

3、ArkTS语言介绍

目录 基础知识函数函数声明可选参数Rest参数返回类型箭头函数&#xff08;又名Lambda函数&#xff09;闭包 类字段字段初始化getter和setter继承父类访问方法重写方法重载签名可见性修饰符&#xff08;Public、Private、protected&#xff09; 基础知识 ArkTS是一种为构建高性…...