私は、それらをneo4j組み込みDBにインポートするためにMySQL/Mariaデータベースから300Kレコードをロードする必要があるJavaアプリケーションを持っています。必要なフィールドをすべて取得するには、4つのテーブルを結合する必要があります。それらのそれぞれは、1:1
と他のものとの関係に一致するほぼ300kのレコードを有する。Neo4j OutOfMemoryエラー:GCオーバーヘッドの上限を超えました
これはコードです:
String query = ""
+ "SELECT "
+ " a.field1, "
+ " a.field2, "
+ " a.field3, "
+ " f.field4, "
+ " a.field5, "
+ " a.field6, "
+ " a.field7, "
+ " a.field8, "
+ " a.field9, "
+ " a.field10, "
+ " b.field11, "
+ " b.field12, "
+ " b.field13, "
+ " l.field14, "
+ " l.field15, "
+ " a.field16 "
+ "FROM table1 a "
+ "LEFT OUTER JOIN table2 f ON f.pkTable2 = a.fkTable2 "
+ "LEFT OUTER JOIN table3 b ON b.pkTable3 = a.fkTable3 "
+ "LEFT OUTER JOIN table4 l ON l.pk1Table4 = a.fk1Table4 AND l.pk2Table4 = a.fk2Table4 ";
try (
Connection connection = ds.getConnection();
PreparedStatement statement = connection.prepareStatement(query);
ResultSet rs = statement.executeQuery();
) {
Transaction tx = graphDB.beginTx(); // open neo4j transaction
int count = 0;
int count = 0;
rs.setFetchSize(10000);
while(rs.next()) {
String field1 = rs.getString("field1");
String field2 = rs.getString("field2");
String field3 = rs.getString("field3");
String field4 = rs.getString("field4");
String field5 = rs.getString("field5");
String field6 = rs.getString("field6");
String field7 = rs.getString("field7");
String field8 = rs.getString("field8");
String field9 = rs.getString("field9");
String field10 = rs.getString("field10"); // <-- error comes here
String field11 = rs.getString("field11");
String field12 = rs.getString("field12");
String field13 = rs.getString("field13");
String field14 = rs.getString("field14");
String field15 = rs.getBigDecimal("field15");
String field16 = rs.getBigDecimal("field16");
// process data - insert/update/delete in neo4j embedded DB
if("D".equals(field16)) { // record deleted in mysql db - delete from neo4j too
Map<String, Object> params = new HashMap<String, Object>();
params.put("field1", field1);
graphDB.execute(" MATCH (p:NODELABEL {field1:{field1}}) OPTIONAL MATCH (p)-[r]-() DELETE r,p", params);
} else {
Node node;
if("M".equals(field16)) { // record modified, load the existing node and edit it
node = graphDB.findNode(Labels.NODELABEL, "field1", field1);
} else { // new record, create node from scratch
node = graphDB.createNode(Labels.NODELABEL);
}
node.setProperty("field1", field1);
node.setProperty("field2", field2);
node.setProperty("field3", field3);
node.setProperty("field4", field4);
node.setProperty("field5", field5);
node.setProperty("field6", field6);
node.setProperty("field7", field7);
node.setProperty("field8", field8);
node.setProperty("field9", field9);
node.setProperty("field10", field10);
node.setProperty("field11", field11);
node.setProperty("field12", field12);
node.setProperty("field13", field13);
node.setProperty("field14", field14);
node.setProperty("field15", field15);
}
count++;
if(count % 10000 == 0) {
LOG.debug("Processed " + count + " records.");
tx.success(); // commit
tx.close(); // close neo4j transaction (should free the memory)
tx = graphDB.beginTx(); // reopen the transaction
}
}
// commit remaining records and close the last transaction
tx.success();
tx.close();
} catch (SQLException ex) {
// LOG exception
}
すべてが罰金行くが、輸入は300Kで停止し、約5秒間待機しOutOfMemoryException
をスロー:
java.lang.OutOfMemoryError: GC overhead limit exceeded
at com.mysql.cj.core.util.StringUtils.toString(StringUtils.java:1665)
at com.mysql.cj.core.io.StringValueFactory.createFromBytes(StringValueFactory.java:93)
at com.mysql.cj.core.io.StringValueFactory.createFromBytes(StringValueFactory.java:36)
at com.mysql.cj.core.io.MysqlTextValueDecoder.decodeByteArray(MysqlTextValueDecoder.java:232)
at com.mysql.cj.mysqla.result.AbstractResultsetRow.decodeAndCreateReturnValue(AbstractResultsetRow.java:124)
at com.mysql.cj.mysqla.result.AbstractResultsetRow.getValueFromBytes(AbstractResultsetRow.java:225)
at com.mysql.cj.mysqla.result.ByteArrayRow.getValue(ByteArrayRow.java:84)
at com.mysql.cj.jdbc.result.ResultSetImpl.getString(ResultSetImpl.java:880)
at com.mysql.cj.jdbc.result.ResultSetImpl.getString(ResultSetImpl.java:892)
at org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet.getString(DelegatingResultSet.java:266)
at org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet.getString(DelegatingResultSet.java:266)
at com.js.Importer.importData(Importer.java:99)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
私は外を追加したときに、この例外は思い付いtable3
とtable4
に参加してください。これらの新しい結合の前にエラーはありませんでした。
データを処理しているときにアプリが2GBのRAMと100%のCPUを消費することがわかりました。それが2GBのRAMに達すると、メモリを使い果たします。
私はthis answerと書いてあります。
だから私もちょうどアプリ高いRAMを与えることができるが、これは一種の回避策のようですので、私が代わりに問題を解決したい:コメント欄では、見つけることができます。Tim: Would it be correct to summarise your answer as follows: "It's just like an 'Out of Java Heap space' error. Give it more memory with -Xmx." ?
OP: @Tim: No, that wouldn't be correct. While giving it more memory could reduce the problem, you should also look at your code and see why it produces that amount of garbage and why your code skims just below the "out of memory" mark. It's often a sign of broken code.
私はまた、VisualVMのでアプリをプロファイリングしようと、これは結果であった:
それはのNeo4jは、メモリのオーバーヘッドを避けるために、私は一度に10Kのノードを処理する場合でも、メモリ内のすべてのノードを保っているようです。
このようなことをやめる方法を教えてください。
どのようにしてメモリの問題を解決できますか?メモリの問題を解決するために
https://neo4j.com/docs/operations-manual/current/performance/を読み、[ページのキャッシュサイズ](https://neo4j.com/docs/operations-manual/を削減しようcurrent/reference/configuration-settings /#config_dbms.memory.pagecache.size)を参照してください。 – Leon