使用IEnumerable <object []>上的IDataReader提高SqlBulkCopy的性能

时间:2019-05-31 09:34:14

标签: c# performance sqlbulkcopy

我正在重构一些代码,这些代码以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);
        }

dotTrace输出 dotTrace output

0 个答案:

没有答案