我正在重构一些代码,这些代码以IEnumerable的源格式从动态Excel电子表格或CSV文件中提取数据,然后使用ADO.NET的SqlBulkCopy保存该代码。目前,保存500,000行数据需要近43秒。原始代码将IEnumerable转换为DataTable,然后再将其传递给SqlBulkCopy.WriteToServer(dt)。这种转换过程以及数据的保存也花费了很多时间。要批量复制到的目标表是在批量复制之前重新创建的,没有数据也没有索引(但是有2个默认约束。我尝试将其关闭)。在阅读了有关使用提高速度的数据(仅使用Forward DataReader(IDataReader)来防止将整个对象加载到内存中)以提高速度方面的各种文章(包括使用FastMember)之后,我认为我将为IEnumerable实现自己的对象。我设法将MyDataReader>的准备时间减少到仅一秒钟以上,但是随后我注意到SQLBulkCopy变成了香蕉。我保存的所有时间都转移了,但是这次在SqlBulkCopy.WriteToServer(dt)函数中。我可以看到它被称为11次,对应于11个批次的50000行。尝试读取和写入每个单独的行和列值使其运行460万次,似乎很麻烦。我以为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);
}