Выход из ситуации с SystemOutOfMemoryException при импорте из большого текстового файла в БД

мы используем ZyWall для защиты наших серверов от внешних вторжений. Он генерирует файлы ежедневных журналов огромных размеров, более ГБ, иногда 2 ГБ. Обычно они содержат более 10 миллионов строк. Теперь моя задача написать приложение, которое будет импортировать эти строки в базу данных Oracle. Я пишу это на C#. Что я сейчас делаю:

  1. Я читаю лог-файлы построчно. Я не загружаю весь файл сразу:

    using(StreamReader reader=new StreamReader("C:\ZyWall.log")) { while ((line=reader.ReadLine())!=null) ...... }

  2. Каждую прочитанную строку я разбиваю на части в соответствии с запятыми в ней.

    string[] lines = line.Split(new Char[] { ',' }, 10);

  3. Затем я перебираю массив строк, создаю новую строку для предопределенного объекта DataTable и присваиваю значения массива столбцам в строке. Затем я добавляю строку в таблицу данных.

После того, как все строки прочитаны в таблицу данных, я использую OracleBulkCopy для записи данных в нее в физическую таблицу в базе данных с той же структурой. Но дело в том, что я получаю SystemOutOfMemoryException, когда добавляю строки в объект Datatable, это 3-й шаг. Если я закомментирую 3-й шаг, то в диспетчере задач я увижу, что приложение потребляет стабильный объем памяти, который составляет что-то вроде 17000 К, но если я раскомментирую этот шаг, использование памяти будет расти, если не будет достаточно памяти для выделения. Есть ли еще способ использовать BulkCopy для выполнения этого или мне придется делать это вручную? Я использовал BulkCopy, потому что это намного быстрее, чем вставка строк по одной.


person Mikayil Abdullayev    schedule 25.02.2012    source источник
comment
Судя по вашему описанию, вы не получаете переполнение стека в соответствии с вашим заголовком - простое нехватка памяти сильно отличается.   -  person Jon Skeet    schedule 25.02.2012


Ответы (1)


Если я правильно понимаю, вы загружаете каждую строку в таблицу, которая становится настолько большой, что достигает пределов памяти вашей системы.
Если это так, вы должны найти этот предел. (Например 1000000 строк). Перестаньте читать строки задолго до этого момента и запишите строки, загруженные до сих пор, с помощью OracleBulkCopy. Очистите память и начните заново. Итак, позвольте мне обобщить все с помощью псевдокода.

int lineLimit = GetConfiguration("lineLimit"); 
int lineNumber = 0;
DataTable logZyWall = CreateLogTable();

using(StreamReader reader=new StreamReader("C:\ZyWall.log")) 
{ 
    while ((line=reader.ReadLine())!=null)
    {
        DataRow row = ParseThisLine(line);
        logZyWall.Rows.Add(row);
        lineNumber++;
        if(lineNumber == lineLimit)
        {
            WriteWithOracleBulkCopy(logZyWall);
            logZyWall = CreateLogTable();
            lineNumber = 0;
        }
    }
    if(lineNumber != 0) WriteWithOracleBulkCopy(logZyWall);
}
person Steve    schedule 25.02.2012