Я пишу полную программу извлечения базы данных в Java. База данных - Oracle, и она огромна. В некоторых таблицах ~ 260 миллионов записей. Программа должна создать один файл для каждой таблицы в определенном формате, поэтому использование Oracle Datapump и т. Д. Не вариант. Кроме того, некоторые политики безопасности компании не позволяют писать процедуру PL / SQL для создания файлов на сервере БД для этого требования. Я должен идти с Java и JDBC.
Проблема, с которой я сталкиваюсь, заключается в том, что, поскольку файлы для некоторых таблиц огромны (~ 30 ГБ), у меня почти не хватает памяти почти каждый раз, даже с 20 ГБ Java Heap. Во время создания файла, когда размер файла превышает размер кучи, даже с одной из самых агрессивных политик GC, процесс, кажется, зависает. Например, если размер файла> 20 ГБ, а размер кучи - 20 ГБ, когда использование кучи достигнет максимального размера кучи, его скорость записи составит 2 МБ в минуту или около того, и на этой скорости потребуется несколько месяцев, чтобы полностью извлечь файл.
Я ищу способ преодолеть эту проблему. Любая помощь будет принята с благодарностью.
Вот некоторые подробности конфигурации системы, которую я имею:
Java - JDK1.6.0_14
Конфигурация системы - RH Enterprise Linux (2.6.18), работающая на 4 X Intel Xeon E7450 (6 ядер) @ 2.39GH
RAM - 32 ГБ
База данных Oracle 11g
файл wirting часть кода идет ниже:
private void runQuery(Connection conn, String query, String filePath,
String fileName) throws SQLException, Exception {
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = conn.prepareStatement(query,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(maxRecBeforWrite);
rs = stmt.executeQuery();
// Write query result to file
writeDataToFile(rs, filePath + "/" + fileName, getRecordCount(
query, conn));
} catch (SQLException sqle) {
sqle.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
} catch (SQLException ex) {
throw ex;
}
}
}
private void writeDataToFile(ResultSet rs, String tempFile, String cnt)
throws SQLException, Exception {
FileOutputStream fileOut = null;
int maxLength = 0;
try {
fileOut = new FileOutputStream(tempFile, true);
FileChannel fcOut = fileOut.getChannel();
List<TableMetaData> metaList = getMetaData(rs);
maxLength = getMaxRecordLength(metaList);
// Write Header
writeHeaderRec(fileOut, maxLength);
while (rs.next()) {
// Now iterate on metaList and fetch all the column values.
writeData(rs, metaList, fcOut);
}
// Write trailer
writeTrailerRec(fileOut, cnt, maxLength);
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
fileOut.close();
} catch (IOException ioe) {
fileOut = null;
throw new Exception(ioe.getMessage());
}
}
}
private void writeData(ResultSet rs, List<TableMetaData> metaList,
FileChannel fcOut) throws SQLException, IOException {
StringBuilder rec = new StringBuilder();
String lf = "\n";
for (TableMetaData tabMeta : metaList) {
rec.append(getFormattedString(rs, tabMeta));
}
rec.append(lf);
ByteBuffer byteBuf = ByteBuffer.wrap(rec.toString()
.getBytes("US-ASCII"));
fcOut.write(byteBuf);
}
private String getFormattedString(ResultSet rs, TableMetaData tabMeta)
throws SQLException, IOException {
String colValue = null;
// check if it is a CLOB column
if (tabMeta.isCLOB()) {
// Column is a CLOB, so fetch it and retrieve first clobLimit chars.
colValue = String.format("%-" + tabMeta.getColumnSize() + "s",
getCLOBString(rs, tabMeta));
} else {
colValue = String.format("%-" + tabMeta.getColumnSize() + "s", rs
.getString(tabMeta.getColumnName()));
}
return colValue;
}