我遇到了一个java OutOfMemoryError问题。该程序基本上查看在mysql工作台上运行的mysql表,并查询它们以获取某些信息,然后将它们放入CSV文件中。
程序可以正常使用较小的数据集,但是一旦我使用更大的数据集(记录信息的时间小于40分钟),我就会收到这个错误,这对我说这个问题来自于庞大的数据集和程序没有很好地处理的信息。或者无法按照我的方式处理这些数据。
将Java VM参数设置为-xmx1024m适用于稍微大一些的数据集,但我需要它来处理更大的数据集,但它会产生错误。
以下是我非常确定程序原因的方法:
// CSV is csvwriter (external lib), sment are Statements, rs is a ResultSet
public void pidsforlog() throws IOException
{
String[] procs;
int count = 0;
String temp = "";
System.out.println("Commence getting PID's out of Log");
try {
sment = con.createStatement();
sment2 = con.createStatement();
String query1a = "SELECT * FROM log, cpuinfo, memoryinfo";
rs = sment.executeQuery(query1a);
procs = new String[countThrough(rs)];
// SIMPLY GETS UNIQUE PROCESSES OUT OF TABLES AND STORES IN ARRAY
while (rs.next()) {
temp = rs.getString("Process");
if(Arrays.asList(procs).contains(temp)) {
} else {
procs[count] = temp;
count++;
}
}
// BELIEVE THE PROBLEM LIES BELOW HERE. SIZE OF THE RESULTSET TOO BIG?
for(int i = 0; i < procs.length; i++) {
if(procs[i] == null) {
} else {
String query = "SELECT DISTINCT * FROM log, cpuinfo, memoryinfo WHERE log.Process = " + "'" + procs[i] + "'" + " AND cpuinfo.Process = " + "'" + procs[i] + "'" + " AND memoryinfo.Process = " + "'" + procs[i] + "' AND log.Timestamp = cpuinfo.Timestamp = memoryinfo.Timestamp";
System.out.println(query);
rs = sment.executeQuery(query);
writer = new CSVWriter(new FileWriter(procs[i] + ".csv"), ',');
writer.writeAll(rs, true);
writer.flush();
}
}
writer.close();
} catch (SQLException e) {
notify("Error pidslog", e);
}
}; // end of method
请随时询问您是否需要源代码或更多信息,因为我非常想要解决这个问题!
感谢。
答案 0 :(得分:2)
SELECT * FROM log, cpuinfo, memoryinfo
肯定会给出一个巨大的结果集。它将给出所有3个表中所有行的笛卡尔积。
如果没有看到表格结构(或知道所需的结果),很难确定解决方案,但我怀疑你要么某种连接条件来限制结果集,要么使用UNION
a' LA;
SELECT Process FROM log
UNION
SELECT Process FROM cpuinfo
UNION
SELECT Process FROM memoryinfo
...它将在所有3个表中为您提供Process
的所有不同值。
您的第二个SQL语句看起来也有点奇怪;
SELECT DISTINCT *
FROM log, cpuinfo, memoryinfo
WHERE log.Process = @param1
AND cpuinfo.Process = @param1
AND memoryinfo.Process = @param1
AND log.Timestamp = cpuinfo.Timestamp = memoryinfo.Timestamp
看起来你试图同时从所有3个日志中进行选择,但最终还是选择了另一个笛卡尔积。你确定你得到了你期望的结果集吗?
答案 1 :(得分:1)
您可以使用LIMIT estatementet限制SQL查询返回的结果。
例如:
SELECT * FROM `your_table` LIMIT 100
这将返回前100个结果
SELECT * FROM `your_table` LIMIT 100, 200
这将返回100到200的结果
显然,您可以使用这些值进行迭代,以便无论有多少元素都可以访问数据库中的所有元素。
答案 2 :(得分:0)
我认为你在内存中加载的数据太多了。尝试在sql语句中使用offset
和limit
,以便避免此问题
答案 3 :(得分:0)
您的Java代码正在处理数据库可以更有效地执行的操作。从query1a看,你真正想要的只是独特的过程。 select distinct Process from ...
应足以做到这一点。
然后,仔细考虑该查询中需要哪些表。你真的需要log,cpuinfo和memoryinfo吗?正如Joachim Isaksson所提到的,这将返回这三个表的笛卡尔积,给你x * y * z行(其中x,y和z是这三个表中每一行的行数)和a + b + c列(其中a,b和c是每个表中的列计数)。我怀疑这是你想要或需要的。我假设您可以从一个表或三个表的联合(而不是连接)中获取这些独特的进程。
最后,你的第二个循环和查询本质上是在进行连接,再一次更好,更有效地留给数据库。
答案 4 :(得分:0)
正如其他人所说,以较小的块获取数据可能会解决问题。 这是stackoverflow中讨论此问题的其他线程之一: How to read all rows from huge table?