govindarajan k Ответов: 1

Как избежать ошибки system. outofmemoryexception при очистке и загрузке c# datatable в цикле


Для нашего проекта из C# мы выполняем запрос Oracle SQL и сохраняем результат запроса в выходном файле (CSV, TXT или XML). Поскольку количество записей огромно (например, 2848 489 записей) для некоторых файлов, требуется больше времени, чтобы закончить создание выходного файла. Итак, я попытался извлечь данные в диапазонах (пределах строк) в datatable в dataset и запишите соответствующие данные в выходной файл в цикле. Для каждой итерации я очищаю DataTable, как только данные из него записываются в выходной файл, а затем загружаю новый набор данных.
Но в этом методе (часть кода приведена ниже), основанном на ограничениях строк в цикле, загрузка данных в конкретную итерацию DataTable завершается неудачей.:
'Система.OutOfMemoryException- ошибка, так как процессор и память полностью задействованы. Как избежать этой ошибки? Существует ли какой-либо альтернативный метод создания выходного файла без ошибки памяти?

Что я уже пробовал:

Это часть кода из приложения Windows, которое я создал :
private void button2_Click(object sender, EventArgs e)
        {
            mOraAuth = "Persist Security Info=False;Data Source=" + mOraDataSource.ToString();
            mOraAuth = mOraAuth + ";User Id=" + mOraUserID;
            mOraAuth = mOraAuth + ";Password=";
            mOraAuth = mOraAuth + mOraPassword.ToString() + ";";
            maxRows = 1000; 
            Conn = new OracleConnection(mOraAuth.ToString());
            Conn.Open();
            DataSet ds = new DataSet();
            MainQuery = "SELECT  * FROM t_ic_efeed_wsstandard WHERE JOBFILENAME = 'C416162_GE_WSSTANDARD_20150901.csv' ORDER BY confdate, part_start";
            OracleDataAdapter adapter = new OracleDataAdapter(MainQuery, Conn);

            string Count_Query = "SELECT Count(*) FROM (" + MainQuery + ")";

            OracleCommand Command = new OracleCommand(Count_Query, Conn);
            Command.CommandType = CommandType.Text;
            OracleDataReader Reader = Command.ExecuteReader();
            while (Reader.Read())
            {
                TotalRows = Reader[0].ToString();
            }
            LoopCount =  Convert.ToInt32(TotalRows) / maxRows + 1;
            
            string DataTableName = "MyTable";
            ds.Tables.Add(DataTableName);
            for (DTLoop = 0; DTLoop < LoopCount; DTLoop++)
            {
                if (DTLoop == 0) CurrRow = 1;
                adapter.Fill(ds, CurrRow, (CurrRow + maxRows - 1), DataTableName);
                CurrRow = CurrRow + maxRows;
                CreateCSVFile(ds.Tables[0], AppDomain.CurrentDomain.BaseDirectory + "\\C416162_GE_WSSTANDARD_20150901.csv");
                ds.Tables[0].Clear();
                ds.Tables[0].Dispose();
            }
            ds.Clear();
            ds.Dispose();
            Conn.Close();
        }

govindarajan k

Дополнительный комментарий :
Тестирование проводилось с помощью :

Данные Сведения :
Всего Записей : 2 848 489
Значение MaxRows установлено как: 10000
Количество петель : 285

сведения об ошибке :
Сбой при загрузке данных в DataTable от 650001 до 660000 строк с системой.Произошла ошибка OutOfMemoryException.

Richard MacCutchan

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

1 Ответов

Рейтинг:
1

RickZeeland

Я бы рекомендовал использовать SqlDataReader, см.: [Класс sqldatareader] вместо использования DataTable и DataSet.
Кроме того, я думаю, что Oracle предоставляет такие варианты запросов, как Rownumber или Limit чтобы получить только ограниченное количество записей за один раз.


govindarajan k

Спасибо за ваш ответ, Рикзиленд. Я не использую базу данных SQL Server, но использую соединение с базой данных Oracle для этого проекта.

RickZeeland

Вы правы, тогда это был бы OracleDataReader, смотрите: https://msdn.microsoft.com/en-us/library/system.data.oracleclient.oracledatareader(v=против 110). aspx
См. здесь информацию о разбиении на страницы с помощью Rownum: http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197.html