Я выполняю рефакторинг некоторого кода, который извлекает данные из динамических электронных таблиц Excel или из файла CSV в исходном формате IEnumerable, а затем сохраняет его с помощью SqlBulkCopy из ADO.NET.В настоящее время для сохранения 500 000 строк данных требуется около 43 секунд.Исходный код преобразовал IEnumerable в DataTable перед передачей его в SqlBulkCopy.WriteToServer (dt).Этот процесс преобразования, а также сохранение данных также заняли довольно много времени.Таблица назначения для массового копирования в только что созданную перед массовым копированием без данных и без индексов (но с двумя ограничениями по умолчанию. Я попытался отключить их).После прочтения различных статей (включая использование FastMember) об улучшении скорости с использованием Forward Only DataReader (IDataReader), чтобы предотвратить загрузку всего объекта в память, я подумал, что реализую свою собственную для IEnumerable.Мне удалось сократить время подготовки MyDataReader> до чуть более секунды, но затем я заметил, что SQLBulkCopy собирает бананы.Все время, которое я сохранил, было смещено, но на этот раз внутри функции SqlBulkCopy.WriteToServer (dt).Я вижу, как он вызывается 11 раз, что соответствует 11 партиям по 50000 строк.Похоже, это трогательно пытается прочитать и записать каждое отдельное значение строки и столбца, запустив его 4,6 миллиона раз.Я думал, что IDataReader должен был быть быстрым?Как мне сделать это быстрее?Код и dotTrace ниже:
Пример исходных данных
EnumerableDataReader<object[]>
EnumerableDataReader[0] = object[]{"Column1", "Column2", "Column3", "Column4", "Column5"}
EnumerableDataReader[1] = object[]{"Data1", "Data2", "Data3", "Data4"}
EnumerableDataReader[2] = object[]{"Data1", "Data2", "Data3", "Data4"}
Реализация IDataReader
public class EnumerableDataReader<T> : IDataReader
where T : IEnumerable
{
private IEnumerator<T> _iterator;
public EnumerableDataReader(IEnumerable<T> list)
{
this._iterator = list.GetEnumerator();
}
public void Close()
{
_iterator.Dispose();
}
public bool Read()
{
return _iterator.MoveNext();
}
public void Dispose()
{
Close();
}
public Type GetFieldType(int i)
{
return ((IEnumerable<object>)_iterator.Current)?.ElementAt(i).GetType();
}
public object GetValue(int i)
{
return ((IEnumerable<object>) _iterator.Current)?.ElementAt(i);
}
public int GetValues(object[] values)
{
values = (object[]) (IEnumerable<object>)_iterator.Current;
return values.Length;
}
public int FieldCount
{
get
{
return _iterator.Current != null ? ((IEnumerable<object>) _iterator.Current).Count() : 0;
}
}
Сохранениекод:
public void bulk_copy_data(string destinationTable, IDataReader dt, int fieldCount, FieldMappingInfo fi)
{
try
{
using (SqlBulkCopy bulk = new SqlBulkCopy(Connection(), SqlBulkCopyOptions.TableLock, null))
{
bulk.DestinationTableName = destinationTable;
bulk.BulkCopyTimeout = 500;
bulk.BatchSize = 50000;
for (int i = 0; i < fieldCount - 1; i++)
{
bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping() { SourceOrdinal = i, DestinationOrdinal = i });
}
bulk.WriteToServer(dt);
}
Выход dotTrace ![dotTrace output](https://i.stack.imgur.com/3gNj3.png)