Как добавить SQL-запрос к существующему файлу в Java? - PullRequest
0 голосов
/ 14 июня 2019

В настоящее время я работаю над кодом Java, который позволяет запрашивать базу данных и извлекать ее содержимое в файл.

Пока что нет проблем для небольших запросов.

Но я быстроприходится извлекать большие объемы данных, и я несколько дней пытался реализовать наиболее эффективное решение, чтобы максимально ограничить потребление памяти.

Поскольку, как только я сделаю важный запрос,Память исходного компьютера и целевого компьютера переполнена.

Ява версия Java, которую я использую в среде redhat linux: 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 Hub Receive 1" java.lang.lang.OutOfMemoryError: Пространство кучи Java

Я хотел бы иметь возможность написать, например, 1000 строк на 1000 строк в файле, чтобы не насыщать память.

Зная, чтоиногда размер файлов может достигать 40 ГБ

Время выполнения на самом деле не является проблемой, но потребление памяти является действительно важным критерием.

Я далеко не профессионал в области Java, поэтому я бы хотелнужна небольшая помощь от вас.

Заранее благодарим вас за ваше время

1 Ответ

1 голос
/ 14 июня 2019
  1. построение строки SQL путем объединения строк - это утечка безопасности.Представьте, что эти переменные содержат что-то вроде: "1'; DROP ALL TABLES; --".Даже если вы знаете, что строки «безопасны», код меняется, и вам не следует принимать вредные привычки.Почини это;Вы можете использовать PreparedStatement, чтобы исправить это.

  2. метаданные не бесплатны.Кэшируйте эти вещи.В частности, кешируйте значение rs.getMetaData().getColumnCount().

  3. Для реальной скорости здесь выполните команду SQL, которая указывает механизму БД непосредственно перекачивать эти данные в файл, а затем передает этот файл, еслиэто не на локальном хосте.На самом деле не может идти быстрее, чем это.

  4. вы не можете сбросить после закрытия, а закрытие подразумевает сброс.Вы можете просто удалить строку flush ().

  5. Если ваш размер выборки не слишком большой, в этом коде нет ничего, что указывало бы на ошибку нехватки памяти.Таким образом, это либо повторные вызовы getMetaData (что означает, что кэширование размера столбца решит вашу проблему здесь), либо механизм БД и / или его драйвер JDBC написаны плохо.Я не слышал об интроскопе, поэтому я упоминаю об этом.Если это так, в лучшем случае вы можете использовать SQL OFFSET и LIMIT, чтобы разделить ваш запрос на «страницы» и, таким образом, не получить слишком много результатов сразу, но без ORDER в вашем SQL, технически БДДвижку разрешено менять порядок на вас, и с ним процесс может стать довольно медленным.

...