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

news2025/4/25 22:23:54

原始实现

使用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));
            // 将六个月前的时间转换为Timestamp
            startTime = 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 DESC
        LIMIT #{offset}, #{pageSize}

经过测试

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2342744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微软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项目下载快速通道四、项目搭建教…

什么是Maven

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

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

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

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

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

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

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

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

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

艾蒙顿桌面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是一种为构建高性…

修改了Element UI中组件的样式,打包后样式丢失

修改了Element UI中组件的样式&#xff0c;在本地运行没有问题&#xff0c;但是打包到线上发现样式丢失&#xff08;样式全部不生效、或者有一部分生效&#xff0c;一部分不生效&#xff09;&#xff0c;问题在于css的加载顺序导致代码编译后样式被覆盖了&#xff0c; 解决办法…

【springsecurity oauth2授权中心】jwt令牌更换成自省令牌 OpaqueToken P4

前言 前面实现了授权中心授权&#xff0c;客户端拿到access_token后就能请求资源服务器接口 权限的校验都是在资源服务器上进行的&#xff0c;授权服务器颁发的access_token有限期是2小时&#xff0c;也就是说在2小时之内&#xff0c;不管授权服务器那边用户的权限如何变更都…

诱骗协议芯片支持PD2.0/3.0/3.1/PPS协议,支持使用一个Type-C与电脑传输数据和快充取电功能

快充是由充电器端的充电协议和设备端的取电协议进行握手通讯进行协议识别来完成的&#xff0c;当充电器端的充电协议和设备端的取电协议握手成功后&#xff0c;设备会向充电器发送电压请求&#xff0c;充电器会根据设备的需求发送合适的电压给设备快速供电。 设备如何选择快充…

变量在template里不好使,在setup好使?

问题&#xff1a; 自定义的一个函数 &#xff0c;import导入后 setup里面使用正常 &#xff0c;在template里面说未定义 作用域问题 在 Vue 的模板语法中&#xff0c;模板&#xff08;template &#xff09;里能直接访问的是组件实例上暴露的属性和方法。从代码看&#xff0c…

OpenCV 图形API(53)颜色空间转换-----将 RGB 图像转换为灰度图像函数RGB2Gray()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为灰度。 R、G 和 B 通道值的常规范围是 0 到 255。生成的灰度值计算方式如下&#xff1a; dst ( I ) 0.299 ∗ src…

Trae+DeepSeek学习Python开发MVC框架程序笔记(四):使用sqlite存储查询并验证用户名和密码

继续通过Trae向DeepSeek发问并修改程序&#xff0c;实现程序运行时生成数据库&#xff0c;用户在系统登录页面输入用户名和密码后&#xff0c;控制器通过模型查询用户数据库表来验证用户名和密码&#xff0c;验证通过后显示登录成功页面&#xff0c;验证失败则显示登录失败页面…

超详细mac上用nvm安装node环境,配置npm

一、安装NVM 打开终端&#xff0c;运行以下命令来安装NVM&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash 然后就会出现如下代码&#xff1a; > Profile not found. Tried ~/.bashrc, ~/.bash_profile, ~/.zprofile, ~/.…

hi3516cv610构建音频sample工程代码步骤

hi3516cv610构建音频sample工程代码步骤 sdk版本&#xff1a;Hi3516CV610_SDK_V1.0.1.0 硬件&#xff1a;非es8388 工程代码&#xff1a; 通过网盘分享的文件&#xff1a;audio_easy.zip 链接: https://pan.baidu.com/s/1gx61S_F3-pf6hPyfbGaRXg 提取码: 4gbg --来自百度网盘…

12.QT-Combo Box|Spin Box|模拟点餐|从文件中加载选项|调整点餐份数(C++)

Combo Box QComboBox 表⽰下拉框 核⼼属性 属性说明currentText当前选中的⽂本currentIndex当前选中的条⽬下标.从0开始计算.如果当前没有条⽬被选中,值为-1editable是否允许修改设为true时, QComboBox 的⾏为就⾮常接近 QLineEdit ,也可以 设置 validatoriconSize下拉框图标…