我目前正在研究一个Java代码,该代码使我可以查询数据库并将其内容提取到文件中。
到目前为止,对于小请求没有问题。
但是我将很快不得不提取大量数据,并且我已经尝试了几天来实施最有效的解决方案,以便尽可能地限制内存消耗。
由于我提出了重要要求,因此源计算机和目标计算机的内存已饱和。
我在redhat linux环境上使用的Java版本是java-1.8.0
到目前为止,我已经能够将查询结果重定向到文件。但是经过大量的文档整理,我可以看到有很多不同的方法可以限制内存消耗。
DriverManager.registerDriver(new
com.wily.introscope.jdbc.IntroscopeDriver());
Connection conn = DriverManager.getConnection("jdbc:introscope:net//" +
user + ":" + password + "@" + hostname + ":" + port);
String query = "select * from metric_data"
+ " where agent='"
+ agents_filter
+ "' and metric='"
+ metrics_filter
+ "' and timestamp between "
+ queryInterval;
Statement ps=conn.createStatement();
ResultSet rs=ps.executeQuery(query);
rs.setFetchSize(Size);
ResultSetMetaData rsm = rs.getMetaData();
File output = new File("result");
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(output), "UTF-8")), false);
for(int i = 1; i <= rs.getMetaData().getColumnCount(); i++){
String colName = rs.getMetaData().getColumnName(i);
out.print(" " + colName + "\t\t" + "|");
}
while (rs.next()) {
for(int i = 1; i <= rs.getMetaData().getColumnCount(); i++){
String colValue = rs.getString(i);
out.print(" " + colValue + "\t" + "|");
}
out.println();
}
out.close();
out.flush();
rs.close();
ps.close();
conn.close();
当前,请求已完全加载到内存中,然后重定向到我的文件。但是,一旦请求太重要,我就会收到以下消息:
线程“ PO:client_main Mailman 2”中的异常java.lang.OutOfMemoryError:Java堆空间 线程“ UnknownHub集线器接收1”中的异常java.lang.lang.OutOfMemoryError:Java堆空间
我希望能够在文件中写入1000乘1000的行,以免使内存饱和。
知道文件有时可以达到40gb
执行时间并不是真正的问题,但是内存消耗是一个非常重要的标准。
我远不是一名Java专业人士,所以这就是为什么我需要您的一些帮助。
提前感谢您的时间
答案 0 :(得分:1)
通过串联字符串来构造SQL字符串是安全漏洞。想象一下,这些变量的内容类似于:"1'; DROP ALL TABLES; --"
。即使在这里您知道字符串是“安全的”,代码也会更改,并且您不应该养成不良习惯。解决这个问题;您可以使用PreparedStatement对其进行修复。
元数据不是免费的。缓存这些东西。具体来说,请缓存值rs.getMetaData().getColumnCount()
。
要在此处获得实际速度,请运行一条SQL命令,该命令告诉DB引擎将数据直接泵送到文件中,如果该文件不在本地主机上,则将其传输。真的不能比这快。
关闭后无法刷新,关闭表示刷新。您只需删除flush()行。
假定您的提取大小不是可笑的大,那么此代码中没有任何内容指示发生内存不足错误。因此,要么是重复调用getMetaData(这意味着缓存列大小将在此处解决您的问题),要么是数据库引擎和/或其JDBC驱动程序的编写不正确。我没听说过内窥镜,这就是为什么我提到它。在这种情况下,充其量您可以使用SQL OFFSET
和LIMIT
将查询分成“页面”,因此不会一次捕获太多结果,但是在其中没有ORDER
您的SQL,从技术上讲,允许DB引擎更改您的顺序,使用它,过程可能会变得很慢。