Пакетная вставка в MySQL приводит к ошибкам GC Overhead и / или Java Heap Space

0

Я пытаюсь вставить около 1,9 миллиона строк сразу в виде пакетной вставки в MySQL. Код работает как шарм с 1,7 мили или меньше строк, но я получаю ошибки накладных расходов и/или иногда ошибки Java Heap Space для строк более 1,8 мили.

Код:

    try {
            // triples is of type ArrayList<String>
            String[] tripleToInsert= null;
            for (int i = 0; i < triples.size(); i++) {
                count++;
                tripleToInsert= triples.get(i).split("\\s+");

                /** Insert <s,p,o> into Triples table **/

                preparedStmt.setString(1, tripleToInsert[0].trim());
                preparedStmt.setString(2, tripleToInsert[1].trim());
                preparedStmt.setString(3, tripleToInsert[2].trim());

                preparedStmt.addBatch();
                preparedStmt.clearParameters();

                tripleToInsert=null;
            }


        }
        catch(OutOfMemoryError e)
        {
            System.out.println("OOM error: IN LOADING TO DB function on loop count: " + count);
            e.printStackTrace();
        }

String preEndTime= new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());
        System.out.println("Preprocessing Ended:" + preEndTime);



        //Insert start time
        String startTime= new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());
        System.out.println("Insert Started:" + startTime);

        // execute the prepared statement as a batch
        long[] results = preparedStmt.executeLargeBatch();

        System.out.println("Update Count size: "+ results.length);

        //Insert end time
        String endTime = new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());
        System.out.println("Insert Completed:" + endTime);

Ошибки встречаемости:

    OOM error: IN LOADING TO DB function on loop count: 1888076
java.lang.OutOfMemoryError: GC overhead limit exceeded
    at com.mysql.jdbc.SingleByteCharsetConverter.toBytesWrapped(SingleByteCharsetConverter.java:230)
    at com.mysql.jdbc.StringUtils.getBytesWrapped(StringUtils.java:652)
    at com.mysql.jdbc.PreparedStatement.setString(PreparedStatement.java:4005)
    at LoadNTriplesByScript.loadTriplesByBatches(LoadNTriplesByScript.java:282)
    at LoadNTriplesByScript.insertNTriplesToDB(LoadNTriplesByScript.java:137)
    at LoadNTriplesByScript.main(LoadNTriplesByScript.java:77)

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.lang.Object.clone(Native Method)
    at java.util.TimeZone.clone(TimeZone.java:738)
    at sun.util.calendar.ZoneInfo.clone(ZoneInfo.java:647)
    at java.util.TimeZone.getDefault(TimeZone.java:625)
    at java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:657)
    at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:601)
    at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:580)
    at LoadNTriplesByScript.loadTriplesByBatches(LoadNTriplesByScript.java:330)
    at LoadNTriplesByScript.insertNTriplesToDB(LoadNTriplesByScript.java:137)
    at LoadNTriplesByScript.main(LoadNTriplesByScript.java:77)

Версия Eclipse: Oxygen.1a Release (4.7.1a)

Размеры кучи Java: -Xms2048m -Xmx3072m

Я не уверен, вызвано ли это методом манипуляции String (split()), или если существует метод LIMIT в методах AddBatch() PreparedStatement на no. из рядов на партию. Я установил autoCommit (FALSE), а затем commit() после выполнения PreparedStatement.

Примечание. Я прочитал множество статей, посвященных сообщениям об ошибках в области ОХ и ошибок Java. Приветствуется любое предложение или указатель относительно того, почему это происходит.

Теги:
garbage-collection
heap-memory

1 ответ

0

С очень высокой вероятностью у вас просто закончилась память. Сообщение вводит в заблуждение, так как высокая накладная стоимость GC обычно прост, вызванный отсутствием сбора (вся память используется).

Причиной для пакетной обработки является исключение высоких затрат на одну команду. Что касается производительности, вряд ли имеет значение, если вы используете партии из 1000 или 1000000 строк. Поэтому попробуйте меньшие партии.

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

Обратите внимание, что вы сохраняете в памяти как исходную строку в triples и разделительную в tripleToInsert. С 1,8 метрами и общим объемом 3 ГБ вы можете использовать менее 1500 байт за строку. Учтите, что в Java есть два байта, считайте, что вы храните его дважды, и что всегда есть накладные расходы, поэтому он может работать, возможно, <300 символов в строке (просто догадка).

Вы в основном делаете это правильно, просто для такой огромной партии требуется много памяти. Если это просто импорт, вы можете сэкономить некоторое количество памяти, очистив нерасщепленные тройки, когда они будут потребляться.

Иногда можно использовать встроенный CSV-импорт, предоставляемый БД.

  • 0
    Я пытался иметь меньшие партии, но это не было бы эффективно для больших нет. из партий, не так ли? Кроме того, данные не находятся в CSV для прямой загрузки с использованием скрипта LOAD. Таким образом, даже если я конвертирую в CSV и затем загружаю его ... это будет просто компромисс между временем вставки и временем загрузки. Другое дело, что из-за некоторого уменьшения размера строки, было бы меньше шансов получить ошибки GC и Heap, я думаю.
  • 0
    @Prathameshdhanawade Как я уже писал, пакетная обработка предназначена для уменьшения накладных расходов на каждую команду. Без партий накладные расходы составляют x , с одной огромной партией - x/1.8e6 , с партиями размера 1000, это x/1000 . Так что это то, что я попробую первым. +++ Экспорт в CSV немного уродлив, но может иметь смысл и может быть самым простым решением. Преимущество заключается в том, чтобы держать вашу Java занятой в течение кратчайшего времени. +++ Оптимизация потребления памяти может помочь, но когда ваши данные сильно растут, вы снова столкнетесь с той же проблемой.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню