7

我正在寻找通过 c# 加载批量数据的最快方法。我有这个脚本可以完成这项工作,但速度很慢。我阅读了 SqlBulkCopy 是最快的证词。
1000 条记录 2.5 秒。文件包含接近 5000 到 250k 的记录 有哪些可以减慢速度的东西?

表定义:

CREATE TABLE [dbo].[tempDispositions](
    [QuotaGroup] [varchar](100) NULL,
    [Country] [varchar](50) NULL,
    [ServiceGroup] [varchar](50) NULL,
    [Language] [varchar](50) NULL,
    [ContactChannel] [varchar](10) NULL,
    [TrackingID] [varchar](20) NULL,
    [CaseClosedDate] [varchar](25) NULL,
    [MSFTRep] [varchar](50) NULL,
    [CustEmail] [varchar](100) NULL,
    [CustPhone] [varchar](100) NULL,
    [CustomerName] [nvarchar](100) NULL,
    [ProductFamily] [varchar](35) NULL,
    [ProductSubType] [varchar](255) NULL,
    [CandidateReceivedDate] [varchar](25) NULL,
    [SurveyMode] [varchar](1) NULL,
    [SurveyWaveStartDate] [varchar](25) NULL,
    [SurveyInvitationDate] [varchar](25) NULL,
    [SurveyReminderDate] [varchar](25) NULL,
    [SurveyCompleteDate] [varchar](25) NULL,
    [OptOutDate] [varchar](25) NULL,
    [SurveyWaveEndDate] [varchar](25) NULL,
    [DispositionCode] [varchar](5) NULL,
    [SurveyName] [varchar](20) NULL,
    [SurveyVendor] [varchar](20) NULL,
    [BusinessUnitName] [varchar](25) NULL,
    [UploadId] [int] NULL,
    [LineNumber] [int] NULL,
    [BusinessUnitSubgroup] [varchar](25) NULL,
    [FileDate] [datetime] NULL
) ON [PRIMARY]

这是代码

    private void BulkLoadContent(DataTable dt)
    {
        OnMessage("Bulk loading records to temp table");
        OnSubMessage("Bulk Load Started");
        using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
        {
            bcp.DestinationTableName = "dbo.tempDispositions";
            bcp.BulkCopyTimeout = 0;
            foreach (DataColumn dc in dt.Columns)
            {
                bcp.ColumnMappings.Add(dc.ColumnName, dc.ColumnName);
            }
            bcp.NotifyAfter = 2000;
            bcp.SqlRowsCopied += new SqlRowsCopiedEventHandler(bcp_SqlRowsCopied);
            bcp.WriteToServer(dt);
            bcp.Close();
        }
    }
4

7 回答 7

8

您对该表有任何索引、触发器或约束吗?

这将导致插入速度变慢 - 尤其是聚集索引会受到伤害。当爆破你正在做的数据量时,最好先删除索引,然后再重新应用它们。

关于它的一篇好文章在这里: What's the faster way to bulk insert a lot of data in SQL Server (C# client)

于 2010-04-22T16:49:13.480 回答
4

如果您有大量数据,将批量大小设置为相当大的数字可能会有所帮助:

bcp.BatchSize = 10000;
于 2011-03-30T13:44:25.807 回答
1

可以减慢批量复制的事情: - 表上的全文索引 - 插入时的触发器 - 外键约束

于 2010-04-22T16:51:05.190 回答
1

我注意到尝试刷新大型数据集最初要快得多,但随着时间的推移会大大减慢。我发现使用缓冲方法可以适度提高性能,在同一连接下一次只提供几千条记录。随着时间的推移,它似乎使每批事务的时间减少,这(随着时间的推移)提高了性能。在我的解决方案中,我注意到在使用此方法将大约 7,500,000 条相同类型的记录保存到同一个数据库时,相同的未缓冲方法将保存大约 5,000,000 条记录。希望这可以帮助某人。

public void flush_DataTable(DataTable dt, string tableName)//my incoming DTs have a million or so each and slow down over time to nothing. This helps.
    {  int bufferSize = 10000;
        int bufferHigh = bufferSize;
        int lowBuffer = 0;
        if (dt.Rows.Count >= bufferSize)
        {  using (SqlConnection conn = getConn())
            {   conn.Open();
                while (bufferHigh < dt.Rows.Count)
                {
                    using (SqlBulkCopy s = new SqlBulkCopy(conn))
                    {   s.BulkCopyTimeout = 900;
                        s.DestinationTableName = tableName;
                        s.BatchSize = bufferSize;

                        s.EnableStreaming = true;
                        foreach (var column in dt.Columns)
                            s.ColumnMappings.Add(column.ToString(), column.ToString());
                        DataTable bufferedTable = dt.Clone();
                        for (int bu = lowBuffer; bu < bufferHigh; bu++)
                        {
                            bufferedTable.ImportRow(dt.Rows[bu]);
                        }
                        s.WriteToServer(bufferedTable);
                        if (bufferHigh == dt.Rows.Count)
                        {
                            break;
                        }
                        lowBuffer = bufferHigh;
                        bufferHigh += bufferSize;

                        if (bufferHigh > dt.Rows.Count)
                        {
                            bufferHigh = dt.Rows.Count;
                        }
                    }
                }
                conn.Close();
            }
        }
        else
        {
            flushDataTable(dt, tableName);//perofrm a non-buffered flush (could just as easily flush the buffer here bu I already had the other method 
        }
    }
于 2016-08-08T11:38:56.653 回答
0

我在这里建议的 IDataReader 实现如何实现 IDataReader?也许对你有帮助。我将它与 SqlBulkCopy 一起使用,如下所示:

using (MyFileDataReader reader = new MyFileDataReader(@"C:\myfile.txt"))
 {
      SqlBulkCopy bulkCopy = new SqlBulkCopy(connection);
      bulkCopy.DestinationTableName = "[my_table]";
      bulkCopy.BatchSize = 10000;

      bulkCopy.WriteToServer(reader);

      bulkCopy.Close();

 } 
于 2013-05-22T15:57:47.963 回答
0

设置 BatchSize 或 NotifyAfter 都会导致速度变慢。

如果你有一个数据阅读器,你可以用一个行计数数据阅读器包装它来获取进度。

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
{
    bulkCopy.EnableStreaming = true;
    bulkCopy.BulkCopyTimeout = 0;
    using (var reader = new MyRowCountDataReader(dataReader))
    {
        reader.NotifyAfter = 1000;
        reader.RowRead += (sender, args) => { ... };
        bulkCopy.WriteToServer(reader);
    }
}
于 2020-01-14T18:59:49.130 回答
0

我刚有过类似的经历。 SqlBulkCopy一个表很好,但另一个表复制相同数量的记录至少要慢 10 倍。

慢表确实有非聚集索引和触发器,但禁用它们并没有产生任何明显的区别。

原来慢表有六NVARCHAR(MAX)列。我实际插入的数据都很短,所以我将列更改为NVARCHAR(500).

等等瞧!慢表的性能得到改进以匹配其他表 - 至少提高了 10 倍的速度。

于 2022-02-17T11:39:38.253 回答