Ответ 1
Думаю, вы можете использовать то же решение, что этот. Прокручиваемый набор результатов.
Мне поручено преобразовать огромную таблицу в пользовательский XML файл. Я буду использовать Java для этой работы.
Если я просто выдаю запрос "SELECT * FROM", он может вернуть огромное количество данных, которые в конечном итоге вызывают OOM. Интересно, есть ли способ, с помощью которого я могу обработать запись сразу после ее появления и удалить запись из памяти после этого во время процесса получения sql?
--- отредактировано 13.07.2009
Позвольте мне уточнить мой вопрос. У меня 1 сервер сервера и 1 сервер приложений. Когда я выдаю запрос выбора в приложении, данные будут перемещаться с сервера db на сервер приложений.
Я верю (исправьте меня, если я ошибаюсь) ResultSet должен будет дождаться получения всех записей в запросе. Даже если мы установили размер выборки как 4, для таблицы с 1000 записями, у нас все еще есть 1000 записей в кучевой памяти сервера приложений, правильно ли это? Размер Fetch влияет только на количество обратных рейсов с/на сервер db.
Мой вопрос в том, как начать обработку на этом 4 (или любом количестве) записей сразу после его поступления на сервер приложений и избавить его от освобождения памяти на сервере приложений?
Думаю, вы можете использовать то же решение, что этот. Прокручиваемый набор результатов.
С более подробной информацией я могу получить более полезный ответ.
Если вы используете MySQL:
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
из http://www.oracle.com/technology/tech/java/sqlj_jdbc/htdocs/jdbc_faq.html:
java.util.Properties info = new java.util.Properties();
info.put ("user", "scott");
info.put ("password","tiger");
info.put ("defaultRowPrefetch","15");
getConnection ("jdbc:oracle:oci:@",info);
Если вы используете JDBC, вы можете использовать ResultSet с курсором, который вы перебираете по одной записи за раз. Вы должны убедиться, что тогда вы записываете свой XML файл в файл по одной записи за раз, а не с помощью DOM для создания XML.
Одно эмпирическое правило, которое я узнал из моего опыта, заключается в том, что вы НИКОГДА не приводите ВСЕ данные из базы данных на ваш сервер приложений. Одна вещь, которую вы можете сделать, это реализовать процедуру для размещения своих данных.
Вы можете привести одну страницу данных, содержащих около 1000-5000 записей, обработать их, а затем снова извлечь данные для следующей страницы.
Концепция экспорта всей таблицы. (Примечание для экспертов: я знаю о его недостатках.)
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
public class FullTableExport {
public static String toXML(String s) {
if (s != null) {
StringBuilder b = new StringBuilder(s.length());
for (int i = 0, count = s.length(); i < count; i++) {
char c = s.charAt(i);
switch (c) {
case '<':
b.append("<");
break;
case '>':
b.append(">");
break;
case '\'':
b.append("'");
break;
case '"':
b.append(""");
break;
case '&':
b.append("&");
break;
default:
b.append(c);
}
}
return b.toString();
}
return "";
}
public static void main(String[] args) throws Exception {
String table = "CUSTOMER";
int batch = 100;
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@server:orcl", "user", "pass");
PreparedStatement pstmt = conn.prepareStatement(
"SELECT /*+FIRST_ROWS(" + batch + ") */ * FROM " + table);
ResultSet rs = pstmt.executeQuery();
rs.setFetchSize(batch);
ResultSetMetaData rsm = rs.getMetaData();
File output = new File("result.xml");
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(output), "UTF-8")), false);
out.printf("<?xml version='1.0' encoding='UTF-8'?>%n");
out.printf("<table name='%s'>%n", toXML(table));
int j = 1;
while (rs.next()) {
out.printf("\t<row id='%d'>%n", j++);
for (int i = 1; i <= rsm.getColumnCount(); i++) {
out.printf("\t\t<col name='%s'>%s</col>%n",
toXML(rsm.getColumnName(i)),
toXML(rs.getString(i)));
}
out.printf("\t</row>%n");
}
out.printf("</table>%n", table);
out.flush();
}
}
Изменить Недостатки (спасибо @J.S.):
На каком этапе происходит ошибка OOM, находится ли она в поиске или обработке данных в XML файле?
Если его извлечение данных, получите данные в пакетах. Сначала выведите общее количество строк, закажите выделение с помощью первичного ключа и ограничьте количество строк, выбранных для жевательных размеров.
Если при создании файла XML отправьте XML node каждого клиента в System.out.println, не храните его в памяти. Запустите программу через запятую и переадресуйте весь вывод в файл;
java MyConverter > results.txt
По мере того, как вы зацикливаете запись, все сохраняется в файле.