У меня есть функция, которая сохраняет все записи из таблицы SQL, чтобы листать Excel с помощью EPPlus. Если я экспортирую небольшое количество данных, все работает нормально, но с 200 + столбцами и 500 000+ строк я получаю исключение OutOfMemory.EPPlus сохраняет два миллиона строк с 200 + столбцами, которые могут быть привязаны к нескольким файлам excel.
Я хотел бы изменить свой код, чтобы иметь возможность сохранять 50 000 записей на файл.
Вот мой код, который работает для небольших данных:
private Task SaveAsync(string tableName)
{
return Task.Run(() =>
{
try
{
using (var conn = new SqlConnection(_connectionString))
{
using (var cmd = new SqlCommand(string.Format(DataQuery, tableName), conn))
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 360;
conn.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
var fileName = string.Format(TargetFile, tableName);
if (File.Exists(fileName))
{
File.Delete(fileName);
}
sdr.Read();
var numberOfRecordsInTable = sdr.GetInt32(0);
sdr.NextResult();
using (ExcelPackage pck = new ExcelPackage(new FileInfo(fileName)))
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Results");
int count = sdr.FieldCount;
int col = 1, row = 1;
for (int i = 0; i < count; i++)
{
ws.SetValue(row, col++, sdr.GetName(i));
}
row++;
col = 1;
while (sdr.Read())
{
for (int i = 0; i < count; i++)
{
var val = sdr.GetValue(i);
ws.SetValue(row, col++, val);
}
row++;
col = 1;
}
//autosize
ws.Cells[ws.Dimension.Address].AutoFitColumns();
//autofiltr
ws.Cells[1, 1, 1, count].AutoFilter = true;
}
}
conn.Close();
}
}
}
catch (Exception e)
{
Debug.WriteLine("Error at: " + Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(e);
}
});
}
и мой модифицированный код, который расщепляет записи 50 000 на файл:
private Task SaveAsync2(string tableName)
{
return Task.Run(() =>
{
try
{
using (var conn = new SqlConnection(_connectionString))
{
using (var cmd = new SqlCommand(string.Format(DataQuery, tableName), conn))
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 360;
conn.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
var fileName = string.Format(TargetFile, tableName,"");
if (File.Exists(fileName))
{
File.Delete(fileName);
}
sdr.Read();
var max = sdr.GetInt32(0);
int filesCount = 1;
if (max > 50000)
{
fileName = string.Format(TargetFile, tableName, filesCount);
}
sdr.NextResult();
ExcelPackage pck = new ExcelPackage(new FileInfo(fileName));
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("RESULTS");
int count = sdr.FieldCount;
int col = 1, row = 1;
for (int i = 0; i < count; i++)
{
ws.SetValue(row, col++, sdr.GetName(i));
}
row++;
col = 1;
while (sdr.Read())
{
for (int i = 0; i < count; i++)
{
var val = sdr.GetValue(i);
ws.SetValue(row, col++, val);
}
row++;
col = 1;
if (row > 50000)
{
pck.Save();
filesCount++;
fileName = string.Format(TargetFile, tableName, filesCount);
pck = new ExcelPackage(new FileInfo(fileName));
ws = pck.Workbook.Worksheets.Add("RESULTS");
count = sdr.FieldCount;
col = 1;
row = 1;
for (int i = 0; i < count; i++)
{
ws.SetValue(row, col++, sdr.GetName(i));
}
row++;
col = 1;
}
}
//autosize
ws.Cells[ws.Dimension.Address].AutoFitColumns();
//autofiltr
ws.Cells[1, 1, 1, count].AutoFilter = true;
pck.Save();
}
}
conn.Close();
}
}
catch (Exception e)
{
Debug.WriteLine("Error at: " + Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(e);
}
});
}
в основном это работает отлично, но в первой версии мой код я использовал все внутри оператора using
, когда во второй версии я вызываю тот же код дважды.
- Как я могу исправить свой код, чтобы удалить дубликат кода и поместить все внутри.
- Могу ли я добавить следующий набор (50 000 записей) в качестве нового рабочего листа вместо создания нового файла?
- Что было бы ограничением EPPlus при сохранении данных в файл?
rows x columns
? Я нашел информацию о том, что EPPlus должен обрабатывать более миллиона строк, но не столько столбцов, сколько у меня. Я думаю, что я могу экспортировать миллионы строк с одним столбцом, но для 200 + столбцов для меня 50 000 строк - это ограничение. Мне интересно, есть ли число (строки x столбцов), которые будут ограничением, в котором мой экспорт будет работать нормально. Я хочу, чтобы эта функция экспорта была универсальной, поэтому, когда я передаю данные с 50 столбцами, она будет экспортировать, например, 100 000 строк на файл, а для 2 столбцов она будет экспортировать полмиллиона файлов.
Благодарим вас за это. Я не знал, что могу использовать «Func» и «Action» таким образом. Я попытаюсь изменить свой код, используя ваш ответ. Прямо сейчас Создаем временный список для хранения данных, которые передаются действию 'savefile'. Могут ли выполняться такие же функции без дополнительных временных переменных? – Misiu
Что будет пределом EPPlus? 'row x columns'? Я нашел информацию о том, что EPPlus должен обрабатывать более миллиона строк, но не столько столбцов. Я думаю, что я могу экспортировать миллионы строк с одним столбцом, но для 107 столбцов для меня 50 000 строк - это ограничение. Мне интересно, есть ли число (строки x столбцов), которые будут ограничением, в котором мой экспорт будет работать нормально. Я хочу, чтобы эта функция экспорта была универсальной, поэтому, когда я передаю данные с 50 столбцами, она будет экспортировать, например, 100 000 строк на файл, а для 2 столбцов она будет экспортировать полмиллиона файлов. – Misiu
@Misiu Да, его временные переменные, которые являются недостатком этого подхода, но поскольку вы используете последовательный читатель, его трудно обойти без какого-либо повторяющегося кода. Что касается фактического предела, то его трудно сказать точно, поскольку он является функцией не только r x c, но и содержимого, то есть строк и чисел. Даже строки являются вариантами, поскольку Excel использует пул строк, поэтому уникальность строк также влияет на него. Я обычно попадаю в стену около 60 тыс. Строк с 150 колонками. – Ernie