java 结果集 returns 大量数据时出现堆大小问题
java Heap Size Issue when result set returns large number of data
我有一个 java-spring-hibernate 网络应用程序,它调用我的 sql 存储过程,该存储过程调用用户特定的 "event" 信息。
要求是将结果集写入文本文件并将其发送到一个 ftp 服务器。我分配了 space 的 4gb,因为堆 size.I 无法分配更多的堆比这个大。但是当存储过程 return 大结果集并从服务器端处理它时,堆大小问题就会出现
当前代码:
1:存储过程return 大结果集(比如几百万行)
2:将其映射到列表
3:将每一行写入一个文本文件。对于单个用户,只写 3 个事件。如果他有超过 3 个事件,请忽略它(请注意我从 mysql 获取基于电子邮件的排序结果集).这个过程我需要在服务器端做
4:结果集大时出现堆大小问题
伪代码:
Stored proc
delete temp table if exist
get public event into temp1 table based on condition
get non public event into temp2 table
create new temp tabletemp 3 by joining temp1 and temp2 and join with user table with some condition and sort it
return select * from temp3 sorted based on email
即使设置了所有必需的索引,通常也需要 20 分钟才能完成
服务器端代码
1:Create File writer object
2:call stored proc
import javax.persistence.EntityManager;
...
..
Query query = entityManager.createNativeQuery("CALL procName(param)");
....
list = query.getResultList();
....
for (final Object[] objects : evntList) {
final EvntDTO dto = new ExactTargetDailyMailDTO(
String.valueOf(objects[0]),
String.valueOf(objects[1]),....,....,);
if dto.getEvntNAme() matches some condition(){
//change event name and other params accordingly
}
eventList.add(dto);
}
...
for (int i = 0; i < eventList.size(); i++) {
Dto dto = eventList.get(i);
count=1;
...
fileContent=dto.getEmail()+appendmore user info +dto.getEventInfo();
while (i + 1 < eventList.size()
&& dto.getEmail().equalsIgnoreCase(remindersList.get(i + 1).getEmail())) {
if (count < 3) {
....
fileContent=fileContent+add next EventInfo
}
...
..
bw.write(fileContent);
bw.newLine();
}
bw.close();
fw.close();
任何人都可以建议我一个更好的计划吗?
因为我想在这个列表中做一些更多的操作(比如如果他有超过 3 个事件忽略它),我不能想到一次获取 1000 或 100 000 个数据并将其写入文件并重复进程
谁能建议我更好的架构和实现方式?
跳过第2步:存入列表。
这样你就可以将所有流式结果集强制到内存中。
如果你在sql之前打开文件,然后为每个rs.next写一行()
您一次只能在内存中存储一些行。
如果超过 3 个事件在删除后跳过。
或
将您的 sql 重写为 return 只有 3 行(使用限制 3)- 这样就没有大的结果集需要处理
对您的代码的一些想法
这是您将对象接收到列表中的部分:
for (final Object[] objects : evntList) {
final EvntDTO dto = new ExactTargetDailyMailDTO(
String.valueOf(objects[0]),
String.valueOf(objects[1]),....,....,);
if(dto.getEvntName() matches some condition(){
//change event name and other params accordingly
}
eventList.add(dto);
稍后您按顺序遍历该列表中的所有事件:
for (int i = 0; i < eventList.size(); i++) {
我不明白为什么不能执行您在 for
循环中执行的操作 而不是 将其添加到列表中。
检查 next 条目是否与 last 条目具有相同的电子邮件的部分 - 你应该能够撤销它查看 current 项是否与 previous 项具有相同的值。这样您就不必 "peek ahead" 在您的列表中。
您似乎也在根据这些电子邮件地址进行一些检查。如果您事先知道 remindersList 中的值,您应该能够将其用作查询的 条件 (AND email LIKE (?, ?, ?...
) 减少行数 returned?
这里的问题不是结果集,而是你的代码。只需摆脱列表,并在结果检索循环内进行条件处理。并且去掉你添加到文件内容的部分,每次直接写入文件即可,而不是延迟。
我有一个 java-spring-hibernate 网络应用程序,它调用我的 sql 存储过程,该存储过程调用用户特定的 "event" 信息。
要求是将结果集写入文本文件并将其发送到一个 ftp 服务器。我分配了 space 的 4gb,因为堆 size.I 无法分配更多的堆比这个大。但是当存储过程 return 大结果集并从服务器端处理它时,堆大小问题就会出现
当前代码:
1:存储过程return 大结果集(比如几百万行)
2:将其映射到列表
3:将每一行写入一个文本文件。对于单个用户,只写 3 个事件。如果他有超过 3 个事件,请忽略它(请注意我从 mysql 获取基于电子邮件的排序结果集).这个过程我需要在服务器端做
4:结果集大时出现堆大小问题
伪代码:
Stored proc
delete temp table if exist
get public event into temp1 table based on condition
get non public event into temp2 table
create new temp tabletemp 3 by joining temp1 and temp2 and join with user table with some condition and sort it
return select * from temp3 sorted based on email
即使设置了所有必需的索引,通常也需要 20 分钟才能完成 服务器端代码
1:Create File writer object
2:call stored proc
import javax.persistence.EntityManager;
...
..
Query query = entityManager.createNativeQuery("CALL procName(param)");
....
list = query.getResultList();
....
for (final Object[] objects : evntList) {
final EvntDTO dto = new ExactTargetDailyMailDTO(
String.valueOf(objects[0]),
String.valueOf(objects[1]),....,....,);
if dto.getEvntNAme() matches some condition(){
//change event name and other params accordingly
}
eventList.add(dto);
}
...
for (int i = 0; i < eventList.size(); i++) {
Dto dto = eventList.get(i);
count=1;
...
fileContent=dto.getEmail()+appendmore user info +dto.getEventInfo();
while (i + 1 < eventList.size()
&& dto.getEmail().equalsIgnoreCase(remindersList.get(i + 1).getEmail())) {
if (count < 3) {
....
fileContent=fileContent+add next EventInfo
}
...
..
bw.write(fileContent);
bw.newLine();
}
bw.close();
fw.close();
任何人都可以建议我一个更好的计划吗?
因为我想在这个列表中做一些更多的操作(比如如果他有超过 3 个事件忽略它),我不能想到一次获取 1000 或 100 000 个数据并将其写入文件并重复进程
谁能建议我更好的架构和实现方式?
跳过第2步:存入列表。
这样你就可以将所有流式结果集强制到内存中。
如果你在sql之前打开文件,然后为每个rs.next写一行() 您一次只能在内存中存储一些行。
如果超过 3 个事件在删除后跳过。
或
将您的 sql 重写为 return 只有 3 行(使用限制 3)- 这样就没有大的结果集需要处理
对您的代码的一些想法
这是您将对象接收到列表中的部分:
for (final Object[] objects : evntList) {
final EvntDTO dto = new ExactTargetDailyMailDTO(
String.valueOf(objects[0]),
String.valueOf(objects[1]),....,....,);
if(dto.getEvntName() matches some condition(){
//change event name and other params accordingly
}
eventList.add(dto);
稍后您按顺序遍历该列表中的所有事件:
for (int i = 0; i < eventList.size(); i++) {
我不明白为什么不能执行您在 for
循环中执行的操作 而不是 将其添加到列表中。
检查 next 条目是否与 last 条目具有相同的电子邮件的部分 - 你应该能够撤销它查看 current 项是否与 previous 项具有相同的值。这样您就不必 "peek ahead" 在您的列表中。
您似乎也在根据这些电子邮件地址进行一些检查。如果您事先知道 remindersList 中的值,您应该能够将其用作查询的 条件 (AND email LIKE (?, ?, ?...
) 减少行数 returned?
这里的问题不是结果集,而是你的代码。只需摆脱列表,并在结果检索循环内进行条件处理。并且去掉你添加到文件内容的部分,每次直接写入文件即可,而不是延迟。