Java记录一次百万级别数据扫表统计的任务

2023-10-26

一. 需求:

统计近200万商家数据, 每日通过查询计费系统更新其余额


二. 技术栈:

抛开分布式定时任务系统Elastic-Job之外, 我们先优先把单系统极限优化挖掘出来, 由于博主接手的是14年的老项目, 本地甚至都无法启动,所以不尝试用高级玩法(数据分片, 消息中间件).

1. Java1.7

2. Mysql数据库5.7


三. 思路分析:

流程如下

1: 扫表

几百万数据表的扫表面临的问题很简单, 当我们分页查询到百万级别以上(甚至几十万)的时候limit 800000, 10 都需要几十秒.测试数据如下

select * from product limit 10, 20   0.016秒
select * from product limit 100, 20   0.016秒
select * from product limit 1000, 20   0.047秒
select * from product limit 10000, 20   0.094秒
//我们已经看出随着起始记录的增加,时间也随着增大, 这说明分页语句limit跟起始页码是有很大关系的,那么我们把起始记录改为40w看下(也就是记录的一般左右)                                    
 
select * from product limit 400000, 20   3.229秒
//再看我们取最后一页记录的时间
select * from product limit 866613, 20   37.44秒

解决方案: 采用覆盖索引的方式快速查询, 并且查询结果只需要自己所需的字段,每次查询100个


SELECT id, user_id,user_name 
FROM product
 WHERE ID > =(select id from product ORDER BY id ASC limit 866613, 1) 
limit 100

大家对大数据量的分页查询可以看下博主这篇文章https://rourou.blog.csdn.net/article/details/110040284

2. 多线程数据处理

我们数据获取到了, 每次扫表就会获得100条数据, 我们如果串行处理效率比较低下,所以这边博主选择的是多线程处理;

多线程处理必须用到线程池(一些runnable, 和new Thread() 不是很好, 因为频繁创建线程销毁线程也是很浪费时间和资源的),

关于线程池的文章, 博主推荐自己写的工具类,非常好用: https://rourou.blog.csdn.net/article/details/81979295

难点一: 线程池参数配置

楼主创建的线程池如下:

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10,
                            0L, TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>(2000), new XXXThreadFactory("countAllSeller"), new ThreadPoolExecutor.CallerRunsPolicy());
                 

线程数其实可以高点,毕竟是IO密集型运算, 但是考虑到计费系统的压力, 所以这边是10; 线程队列为2000, 防止过多创建线程导致OOM(其实不可能的看后续);

难点二: 不能一次性创建过多的对象, 由于是多线程,如果没有收口, 一次性创建太多对象会导致OOM

这边博主用到的是CountDownLauch, 计数就是扫出来的个数, 每一次统计完毕计数一次. 这一轮的100个数据处理完后释放await;下面是楼主代码,也是核心代码

 for (int i = 0;i < sellerPageInfo.getPages() ; i++) {
                List<XXXSellerSimpleDO > xxxSellerDOS= xxxxSellerConfigDAO.findAllSimpleOptimize( 100,i * 100 );
                // 批次结束完才能进行下一波
                final CountDownLatch countDownLatch = new CountDownLatch(xxxSellerConfigDOS.size());
                for (final XXXSellerSimpleDO xxxxSellerConfigDO : xxxSellerDOS) {

                    ThreadPoolUtil.execute(new Runnable() {
                        @Override
                        public void run() {
                           
                            try {
                                // 单个处理
                                countSellerBalance(userId, userName);
                            } catch (ServiceException e) {
                                // 异常直接吞掉
                                serviceLogger.error(String.format("统计指定商家余额发生异常, userId{%s},userName{%s}", userId, userName), e);
                            }
                            // 计数
                            countDownLatch.countDown();
                        }
                    });

                }
                if (i % 50 == 0){
                    serviceLogger.info(String.format("统计指定商家余额进度{%s/%s}", i * 100, totalCount));
                }
                countDownLatch.await();
            }

至此: 代码结束,如有其它问题, 可以给博主留言, 博主几乎每天都在线

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java记录一次百万级别数据扫表统计的任务 的相关文章

  • 如何将变量设置为触发器 MYSQL 内存储过程的结果?

    我这里有一个小问题 我正在为我的数据库工作创建一个触发器 但我不知道如何在触发器内使用存储过程 我想将过程的结果保存在变量中 然后使用稍后在 IF 比较器上变量 这是我的代码 DELIMITER CREATE TRIGGER insert
  • Java 小程序在 Mac 上闪烁

    这个问题很奇怪 问题并非在每个平台上都会发生 我在使用 MacOSX 的 Google Chrome 中出现了这种情况 但在 Safari 中却没有出现这种情况 对于使用 Windows 的朋友来说 在 Google Chrome 上运行得
  • MySQL - 从另一个表插入与常量合并的数据

    我有一个包含一些数据的临时表 products temp 并且我有另一个需要将数据插入其中的表 产品 我需要在新记录上手动设置一些常量 例如vendor id 1等 是否可以在一次请求中插入临时表数据和常量 临时产品 product nam
  • Selenium 和 TestNG 同时使用“dependsOn”和“priority =”问题

    我正在努力在 GUI 自动化测试中实现更好的工作流程控制 我首先从dependsOn开始 但很快发现缺点是如果一个测试失败 则套件的整个其余部分都不会运行 所以我改用 priority 但看到了意外的行为 一个例子 Test priorit
  • Spring HATEOAS 和 HAL:更改 _embedded 中的数组名称

    我正在尝试使用 Spring HATEOAS 构建符合 HAL 的 REST API 经过一番摆弄后我终于开始工作了mostly正如预期的那样 示例 输出现在看起来像这样 links self href http localhost 808
  • 从 CLI 部署 Maven 项目?

    在 IDE 中构建并运行良好 cd home thufir NetBeansProjects HelloMaven JAVA HOME usr lib jvm java 8 openjdk amd64 home thufir local s
  • 避免 @Secured 注释的重复值

    我正在尝试使用以下方法来保护我的服务方法 Secured如下 public interface IUserService Secured ROLE ROLE1 ROLE ROLE2 ResponseEntity saveUser Creat
  • 在Java中如何将字节数组转换为十六进制?

    我有一个字节数组 我希望该数组的每个字节字符串转换为其相应的十六进制值 Java中有没有将字节数组转换为十六进制的函数 byte bytes 1 0 1 2 3 StringBuilder sb new StringBuilder for
  • Time.valueOf 方法返回错误值

    我使用 Time valueOf 方法将字符串 09 00 00 转换为 Time 对象 如下所示 Time valueOf LocalTime parse 09 00 00 当我调用 getTime 来显示我得到的值时 28800000
  • RxJava android mvp 单元测试 NullPointerException

    我是 mvp 单元测试的新手 我想对演示者进行一个非常基本的测试 它负责登录 我只想断言 view onLoginSuccess 这是演示者代码 public LoginPresenter LoginViewContract loginVi
  • Hibernate 标准接受 %% 值

    我正在使用下面的 Hibernate 代码来过滤workFlowName crt add Restrictions like workFlowName workFlow MatchMode ANYWHERE crt is the crite
  • 开发者环境-如何调用/消费其他微服务

    背景 我的环境 Java Play2 MySql 我在 Play2 gt S1 S2 S3 上编写了 3 个无状态 Restful 微服务 S1 消耗来自 S2 和 S3 的数据 因此 当用户点击 S1 时 该服务会异步调用 S2 S3 合
  • 为什么 java.util.Arraylist#clear 按照 OpenJDK 中的方式实现?

    http grepcode com file repository grepcode com java root jdk openjdk 6 b14 java util ArrayList java 473 http grepcode co
  • 为什么不能在 if 语句中声明变量?

    以下 Java 代码无法编译 int a 0 if a 1 int b 0 if a 1 b 1 为什么 不能有任何代码路径导致程序将 1 分配给b无需先声明 我突然想到b的变量范围可能仅限于第一个if声明 但后来我不明白为什么 如果我实在
  • 从 InputStream 中删除换行符

    我喜欢从一个文件中删除所有换行符 对于 n 和 r n java io InputStream 在读取文件时 相应的方法如下所示 param target linkplain File return linkplain InputStrea
  • Java 中序列化的目的是什么?

    我读过很多关于序列化的文章 以及它如何如此美好和伟大 但没有一个论点足够令人信服 我想知道是否有人能真正告诉我通过序列化一个类我们真正可以实现什么 让我们先定义序列化 然后我们才能讨论它为什么如此有用 序列化只是将现有对象转换为字节数组 该
  • Java时区混乱

    我正在运行 Tomcat 应用程序 并且需要显示一些时间值 不幸的是 时间快到了 还有一个小时的休息时间 我调查了一下 发现我的默认时区被设置为 sun util calendar ZoneInfo id GMT 08 00 offset
  • com.sun.xml.ws.message.saaj.SAAJHeader 无法转换为 com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader

    我正在尝试访问第三方 Web 服务 该服务要求我创建一个传递时间信息 用户名和密码的安全标头 我在网上搜索了可行的示例 并尝试了多种方法 我正在尝试使用 Java 6 中内置的内容来做到这一点 我不确定我做错了什么 从 WSDL 生成 We
  • MySqlConnectionStringBuilder - 使用证书连接

    我正在尝试连接到 Google Cloud Sql 这是一个 MySql 解决方案 我能够使用 MySql Workbench 进行连接 我如何使用 C 连接MySqlConnectionStringBuilder 我找不到提供这三个证书的
  • Android ClassNotFoundException:在路径上找不到类

    10 22 15 29 40 897 E AndroidRuntime 2561 FATAL EXCEPTION main 10 22 15 29 40 897 E AndroidRuntime 2561 java lang Runtime

随机推荐

  • linux 配置nginx文件下载页面

    root localhost conf vim nginx conf user nobody worker processes 1 events worker connections 1024 http include mime types
  • 从原理到应用教你了解毫米波雷达

    关注公众号 发现CV技术之美 本文转自西湖大学智能无人系统课题组 作者丁苏生 毫米波雷达基础知识 简介 毫米波雷达 mmWave Rader 采用毫米波作为电磁波发送信号 捕捉并处理电磁波经过路径障碍物的反射信号后可获取目标物体的 速度 距
  • Windows 让cmd启动的程序在后台运行

    在Linux下要使程序后台运行 可通过 java jar Client jar 来实现 在Windows下 则通过 start b java jar Client jar 来实现 20181227更新 这里说的后台运行是指在当前Termin
  • spring 配置

    不配置 启动事务 会报错 404 启用事务管理 EnableTransactionManagement SpringBootApplication scanBasePackages w sh EnableJpaRepositories ba
  • CentOS7安装redis5.0并且搭建集群

    记录在两台虚拟机 版本 CentOS7 上搭建Redis集群 Redis版本 redis 5 0 4 过程如下 1 下载安装 首先在一台虚拟机A IP 192 168 1 103 上新建目录redis 接着进入该目录下 下载redis 5
  • openmp设置线程数目_线程池的参数、配置、基本概念

    线程池的概念和工作机制 概念 首先系统空闲时在创建大量线程 这些线程的集合成为线程池 线程的生老病死都由线程池来决定 工作机制 当有任务到来时 提交给线程池 由线程池来指定线程执行任务 线程池会在内部寻找是否有可以执行任务的线程 任务执行完
  • vue+go-gin+nginx实现后台管理系统

    前后端分离的经典后台管理系统 主要用到的技术和组件 前端 vuejs 组件element ui ant vue axios 后端 golang 框架go gin swagger组件 服务代理 nginx 过程中的疑难问题和关键点记录 一 n
  • IOS_swift文件系统

    func files 应用根目录 let dir NSHomeDirectory NSLog dir dir 文档目录 let doc NSSearchPathForDirectoriesInDomains DocumentDirector
  • HTML制作简单的页面

    一 HTML页面制作代码部分
  • Java的invoke方法

    如果读一些Java或者相关框架的源码 实际上一定会经常出现invoke方法的调用 在自己或者团队封装框架时 如果有时候弄得不好经常也会报invoke相关的错 invoke方法是干什么的 有什么具体用途 首先要了解invoke方法干什么的以及
  • ERROR! The server quit without updating PID file (/usr/local/mysql-5.5.32/data/zexi.pid).

    mysql启动时报错 root zexi mysql 5 5 32 etc init d mysqld start Starting MySQL ERROR The server quit without updating PID file
  • 数据库组合索引

    索引用于快速找出在某个列中有一特定值的行 不使用索引 MySQL必须从第1条记录开始然后读完整个表直到找出相关的行 还需要考虑每次读入数据页的IO开销 而如果采取索引 则可以根据索引指向的页以及记录在页中的位置 迅速地读取目标页进而获取目标
  • 信用卡评分笔记

    信用卡评分语言 R语言 python 信用卡评分模型 ROC曲线 lift曲线 lorenz曲线 logistic回归 ROC IV WOE gini KS lift
  • SpringBoot 实现启动项目后立即执行方法的几种方式

    在项目开发中某些场景必须要用到启动项目后立即执行方式的功能 如我们需要去初始化数据到redis缓存 或者启动后读取相应的字典配置等 这篇文章主要聊聊实现立即执行的几种方法 一 CommandLineRunner和ApplicationRun
  • 3. C++调试时显示代码所在文件 / 函数 / 行号信息

    1 说明 在执行C 代码时 有时希望知道当前代码所在的文件名 函数名和对应行号位置信息 方便快速定位到代码所在处 想要获取这些信息 可以使用C 提供的一些宏进行获取 2 简单说明 FILE 用于获取当前语句所在源文件的文件名 func 用于
  • 尤雨溪对 2022 Web前端生态趋势是这样看的

    文章目录 前言 开发范式 底层框架方面趋势 基于依赖追踪范式 基于依赖追踪范式 共同点 基于编译的响应式系统 统一模型的优势和代价 基于编译的运行是优化 Vue Vapor Mode input 工具链 原生语言在前端工具链中的使用 工具链
  • pytorch实战-图像分类(二)(模型训练及验证)(基于迁移学习(理解+代码))

    目录 1 迁移学习概念 2 数据预处理 3 训练模型 基于迁移学习 3 1选择网络 这里用resnet 3 2如果用GPU训练 需要加入以下代码 3 3卷积层冻结模块 3 4加载resnet152模 3 5解释initialize mode
  • imagej得到灰度图数据_ImageJ的高级使用方法

    今天我们继续来聊一聊ImageJ的高阶使用技巧 问题三 为什么总是全部圈起来的灰度值 有没有大神指导呢求助 本问题涉及免疫印迹 Western Blot 分析 提问者不能分别得到每个条带的值 灰度值0为纯黑 255为纯白 灰度值与光密度值
  • 网页数据库服务器连接超时,数据库服务器连接超时

    数据库服务器连接超时 内容精选 换一换 执行以下步骤创建数据库连接 单击工具栏上的或按 Ctrl N 连接到数据库服务器 弹出 新建 选择数据库连接 对话框 建立连接时 如果首选项文件损坏或首选项值无效 会显示如下错误信息 提示用户首选项值
  • Java记录一次百万级别数据扫表统计的任务

    一 需求 统计近200万商家数据 每日通过查询计费系统更新其余额 二 技术栈 抛开分布式定时任务系统Elastic Job之外 我们先优先把单系统极限优化挖掘出来 由于博主接手的是14年的老项目 本地甚至都无法启动 所以不尝试用高级玩法 数