rt ,
遇到个问题,需要查询 100 条记录查到内存中,然后进行计算。我内存很小,总是 oom 。就是单纯的内存不够。有啥好办法吗?
mat 工具打开 dump ,里面全是 mysql 的 jdbc 对象。。。
最高峰 300w 条,也没啥精力再去弄大数据啥的了。老板只给了 8g 。
小弟能想到的就是,分批查询,一批一批计算。靠谱吗?
有什么好办法吗,大佬们
1
soulzz 2022-03-20 19:49:47 +08:00
加机器 swap 慢就慢
不会崩 |
4
heyjei 2022-03-20 20:21:17 +08:00
用存储过程把计算推到数据库实现,不要用 Java 计算。
|
5
jetyang 2022-03-20 21:09:52 +08:00
分批计算当然靠谱
|
6
RedBeanIce 2022-03-20 21:10:49 +08:00
关键词,代码中的大事务问题
|
7
CEBBCAT 2022-03-20 21:18:22 +08:00
@frank1256 他少说了个“的”字,“加机器的 swap”
另外,8G 也不算小了吧,我觉得甚至还挺大,一次一百条,平均下来一条数据能拥有 80M 内存。我想问问你,你说的内存里全是 JDBC 是什么意思?我离开 Java 好久了,JDBC 不是连接数据库的吗?你没用连接池吗?或者没有对连接池做单例吗? 你可以讲讲你处理数据的方式吗?我怀疑是不是你程序写得有问题 |
8
hidemyself 2022-03-20 21:19:09 +08:00 1
ResultSet.TYPE_FORWARD_ONLY
ResultSet.CONCUR_READ_ONLY 流式查询 /游标查询 不知道满不满足你的要求 |
9
miao1007 2022-03-20 21:21:06 +08:00
写一个 flink 的 jar,单独部署
|
10
janus77 2022-03-20 21:35:26 +08:00
分批就分批呗,慢点来就行了,老板问你就说我电脑太差了没办法
|
11
sagaxu 2022-03-20 21:39:49 +08:00
100 条跟 300w 也不搭啊
|
12
DonaldY 2022-03-20 22:21:53 +08:00
1.先计算一次加载容量,100 条 大对象,大概多大。
2.看 GC 算法,一般调大 老年代的容量,计算出 GC ( STW )的时间 3. 任务进队列,每次执行 x 个任务。 |
14
frank1256 OP @CEBBCAT 目前就是直接读了数据库,然后一口气查了 100 多万条,然后做计算。要是有几个线程一起查,就 oom 了
|
15
frank1256 OP @hidemyself 这个我没试过,我来看看
|
17
liprais 2022-03-20 22:42:45 +08:00 via iPhone
写个 sql 算完事
|
18
misaka19000 2022-03-20 22:45:24 +08:00
信息太少了,不好判断
拆分计算是个办法 |
20
Junzhou 2022-03-20 23:11:02 +08:00
100w 条数据之间有强关联性吗? 如果不是,就分批吧。
|
21
leaves615 2022-03-20 23:14:04 +08:00
文件缓存、流计算
|
22
leaves615 2022-03-20 23:14:36 +08:00
只读取用于计算的字段。
|
23
matrix67 2022-03-20 23:17:46 +08:00
这是挟泰山以超北海么😥
|
24
frank1256 OP @CEBBCAT 大佬我不太明白你说的负载是啥。就是现在的情况是,物理机 8g ,我给的堆内存 7g ,我有个需求,统计单表 30 天的记录的维度指标。比如 30 天内的,top10 ,平均值之类的。需求的某些字段还会在其他的表或者缓存里。有些还要计算公式,用 sql 太麻烦了。就打算读到内存里去计算。但是数量特别大的时候就会内存不够。实际情况里,程序还有其他地方用到缓存,或者还有其他的 query ,也就是说我这个统计能用的缓存很少。
|
26
night98 2022-03-20 23:30:56 +08:00
10 个线程每个线程查 100 条,然后更新原子变量,完事。一次性加载一百万条,只能加钱。
|
27
Brian1900 2022-03-21 03:56:14 +08:00
LIMIT 分批就行了吧,想要一次性读就得加机器呗
|
28
msg7086 2022-03-21 04:13:20 +08:00
如果对性能要求高,就加内存。内存才多少钱,一台 384G 内存的服务器也就几百刀就能买到。
如果要省钱,那就先分批读出来写入单独的数据库中(相当于做数据快照),然后再慢慢分批处理算结果。 |
29
lsk569937453 2022-03-21 04:19:42 +08:00
这种百万级别数据的统计直接大数据计算平台(hardoop/spark)搞起啊
|
30
mingl0280 2022-03-21 04:45:14 +08:00 via Android 1
为啥要一次读 100 万再计算?这是什么神奇的操作?
|
31
mingl0280 2022-03-21 04:46:17 +08:00 via Android 2
@frank1256 据我所知常见的统计学指标没有任何一个需要加载 100 万数据才能计算的
|
32
xuanbg 2022-03-21 07:07:44 +08:00
为啥不写 sql 去统计?
|
33
gam2046 2022-03-21 07:27:38 +08:00
一次业务操作需要读取百万条记录显然是不合理的。尝试业务流程上的优化。如果只是一些统计汇总的任务,完全没必要把所有记录加载到内存后处理。流式的处理并不需要什么内存空间。甚至还不如直接在数据库中汇总后再返回。
|
34
sagaxu 2022-03-21 08:54:47 +08:00 via Android
top10 ,平均值是不需要一次全部读入内存的,可以流式处理
|
35
liangkang1436 2022-03-21 09:03:15 +08:00 via Android
楼主之所以提出这样的问题很有可能就只是一个单独的需求,为了谁一个需求去部署一个大数据框架很不经济,所以常规的做法应该就是每天定时统计,最后前台展示的时候从每天定时统计的表里面去取数据
|
36
summerLast 2022-03-21 09:39:44 +08:00
32 楼给了思路,还有另一种方式 就是 能否 100w 分批查 与分批计算,否的话就让对象尽量的小 而非有过多冗余信息
|
37
X0ray 2022-03-21 09:44:59 +08:00
可以参考下 aggregate function 的思路
|
38
limbo0 2022-03-21 09:48:54 +08:00
典型的 mapreduce
|
39
wqhui 2022-03-21 09:52:07 +08:00
楼上的流式计算 OR 分批汇总计算正解,或者尝试减少单条记录的大小
|
40
frank1256 OP |
41
clf 2022-03-21 10:26:36 +08:00
利用磁盘去做缓存。
POI 在操作大数据导出 excel 的时候就是类似的处理方式,一次性只处理 N 行,其余的数据行会在磁盘里利用文件缓存。 |
43
liuxingdeyu 2022-03-21 11:14:39 +08:00
我觉得分批查靠谱,再就是活用 mapreduce
|
44
cheng6563 2022-03-21 11:21:43 +08:00 1
楼上这么多人就没个说增加 jvm 内存容量限制的吗?
jvm 默认给的堆内存大小为物理内存的 1/4 ,所以啥不管直接加物理内存的收益也只有 1/4 启动命令用 -Xmx6g 参数可以分配 6g 内存给堆。 堆内存一般占 jvm 进程内存的大多数但不是 100%,所以最好再开些 swap 避免占满内存。 |
45
ragnaroks 2022-03-21 13:32:07 +08:00
|
46
kingfalse 2022-03-21 14:59:52 +08:00
自己花钱,再加 8 个 G /狗头
|
47
feitxue 2022-03-21 15:41:55 +08:00
也给几个方向,不一定靠谱.要根据你的实际需求来.
第一种,就是你有提到一个月才跑一次的任务的话,那就每天跑一次,生成你要的日数据,月底的时候汇总这一个月每天的数据.或者安排的没人用系统的时候,凌晨,和其他任务错开执行. 第二种,还是你之前代码,不动,月底的时候申请按量计费的机器,跑完就销毁.不确定你们允不允许这样玩儿,不过这种方式可能对 java 不太友好.或者用云函数,现在有支持 java 的,只是改造成本确实有点大. 其他的 sql 优化的楼上都提到了,我就没啥补充了. |
48
vacuitym 2022-03-21 16:29:51 +08:00
我觉得这个应该定期汇总。数据不多的话每天做日统计,多的话做几小时的统计。然后做月统计。最后只要根据统计的数据再做计算就可以了,我们一般这样做
|
49
fuchaofather 2022-03-21 16:46:34 +08:00 via Android
信息太少了。第一感觉没有必要查 100w 条数据到内存,都是真正需要的吗?
|
50
timsims 2022-03-21 16:58:59 +08:00
xxx 量级数据找 top10 这种不就是经典的面试题。。
|
51
CaptainD 2022-03-21 18:40:10 +08:00
必须要所有数据同时在内存么,如果不需要是否可以分批计算
|
52
sampeng 2022-03-21 18:56:27 +08:00
300w 条记录求平均值,top10.。不都是标准面试算法么。。面试会,实现需求就不会了?
300w 就要上 hadoop 了? 300w 就要大数据了? 300w 哪怕上个 es 也比大数据强啊。。当然,这个量级都不需要。直接硬算酒可以了 1 。分而治之当然靠谱,把数据写入 n 个小文件,再对小文件统计,最后汇总。这一个做法缺点是对数据库压力这个时候会相对较大,如果你的服务器和数据库之间的带宽就 1000M 。会瞬间打满,所以可能会影响业务。 2.limit 控制条目数,开线程内存里去算了然后汇总。坏处是代码写起来复杂,维护相对较麻烦。过了半年可能看不懂自己写的代码。好处就是你可以控制间隔时间,想快就快想慢就慢。 还一个方式。不要侵占你的业务代码,分析是分析,业务时业务。这是完全两个不同的领域。所以: 写个 python 脚本把数据弄出来。。numpy+pandas 。这个数据量,算起来是慢点,但也没有接受不了的程度。 |
53
9c04C5dO01Sw5DNL 2022-03-21 22:20:29 +08:00
可以考虑下预计算(当然,复杂的话不一定可以
|
54
FYFX 2022-03-21 22:56:45 +08:00
统计 30 天记录的维度指标,你这个看着像离线场景啊,用 spark 跑完之后把结果同步到 mysql 或者缓存吧。
|
55
Brentwans 2022-03-21 23:33:05 +08:00
100w 数据就把 8G 搞 oom 了,看下数据自身情况吧,是字符串很多,还是数值都是存成对象了。百万级别的数据不算多,8G 还是可以放下的。
如果想省事,直接 spark 单机跑吧,肯定没问题吧。 |
56
312ybj 2022-03-22 10:33:18 +08:00
1. 分批+多线程处理
这个速度绝对比单线程快,而且资源稳定。 2. 交给大数据 这玩意就是大数据该做的事,Java 不适合大批量数据处理!!!!! |
57
zhangleshiye 2022-03-22 15:10:10 +08:00
如果想在代码里处理的话 ,可以弄张同步中间表,
100w 数据 好比是未经过处理的数据 ->转到中间表(根据各种数据维度 比如时间 一个月处理一个月处理 把这些增量放到中间表里) ,就加一张配置表 比如记录到更新到某某某月了, ->结果就 sum 一下就好了 |