将数据加载到 SQL Server 时的 C# 多线程问题

标签 c# sql multithreading

我有一个包含大约 7030 项的列表。我将列表中的项目保存到 SQL Server 中的表中。我想,我可以使用多线程来加速这个过程,它确实做到了,但是,出现了一个问题。

上传到数据库的项目数没有变化,但是当我运行我的代码后查询表中的记录数时,它总是不同的,说一次上传了 6925,下一次上传了 6831 等等。我不明白为什么会这样。

在我获取数据的类中

 void DatabaseUploadMultiThreading()
    {
        DateTime dtUpload = Program.UploadDate();

        int numThread = 8;          
        int splitNum = _holdingList.Count / numThread;
        int leftOver = _holdingList.Count - (splitNum * (numThread - 1));

        DatabaseWriter[] dbArray = new DatabaseWriter[numThread];
        List<Holding>[] holdingArray = new List<Holding>[numThread];
        Task[] taskDB = new Task[numThread];

        for (int i = 0; i < holdingArray.Length; i++)
        {
            dbArray[i] = new DatabaseWriter(i + 1, dtUpload);

            if (i == (numThread - 1))
                holdingArray[i] = _holdingList.GetRange(i * splitNum, leftOver);
            else
                holdingArray[i] = _holdingList.GetRange(i * splitNum, splitNum);
        }

        for (int i = 0; i < taskDB.Length; i++)
            taskDB[i] = Task.Factory.StartNew(dbArray[i].UploadHoldings, holdingArray[i]);

        try
        {
            Task.WaitAll(taskDB);                   // wait for all the threads to complete
        }
        catch (AggregateException ex)
        {
            ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
        }

    }

DatabaseWriter 类代码片段

 class DatabaseWriter : IDisposable
{
    #region variable declaration
    private SqlConnection _connection;
    private SqlCommand _command;
    private static readonly string _connectionString = "myConnectionString";

    public void UploadHoldings(object objHoldingList)
    {
        List<Holding> holdingList = (List<Holding>)objHoldingList;

        using (_connection = new SqlConnection(_connectionString))
        {
            _connection.Open();

            DataReImported(_dtUpload);

            for (int i = 0; i < holdingList.Count; i++)
            {
                string cmdText = "INSERT INTO HOLDINGS([FUND_CD], [SEDOLCHK], [NOMINAL], [CURR], [PRICE], [DATEU]) " +
                                    "VALUES(@fundcode, @sedol, @nominal, @curr, @price, @dtUpload)";

                _command = new SqlCommand(cmdText, _connection);
                _command.Parameters.Add("@fundCode", SqlDbType.VarChar).Value = holdingList[i].FundCode;
                _command.Parameters.Add("@sedol", SqlDbType.VarChar).Value = holdingList[i].IdSedol;
                _command.Parameters.Add("@nominal", SqlDbType.Decimal).Value = holdingList[i].Nominal;
                _command.Parameters.Add("@curr", SqlDbType.VarChar).Value = holdingList[i].Currency;
                _command.Parameters.Add("@price", SqlDbType.Decimal).Value = holdingList[i].Price;
                _command.Parameters.Add("@dtUpload", SqlDbType.Date).Value = _dtUpload;
                _command.ExecuteNonQuery();

                Console.WriteLine("Thread Number:" + _threadNum + " Security Number uploaded: " + i + " of " + holdingList.Count);
            }
            _connection.Close();
        }
    }



}

最佳答案

我建议这不是使用多个任务的最佳位置。上面显示的代码效率有点低,将其拆分为 Task 对象并并行运行它们,在许多情况下只会使它们彼此绊倒并减慢您的速度或导致其中一个不执行。就像三个臭皮匠同时试图冲进一扇门。

按照上面其他回答者的建议进行基本的、明显的优化,即只创建一次 SqlCommand,并在循环内进行绝对最小化(或者尝试批量加载方法)。并检查 ExecuteNonQuery 返回的值以验证写入的记录数。

关于将数据加载到 SQL Server 时的 C# 多线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22840303/

相关文章:

c# - 如何索引和搜索 Lucene.NET 中的日期时间字段?

SQL:将计数与 Clob 结合使用

sql - ID 字段以 AB_ 为前缀(例如 : AB_00yyhhgdbdbd)

sql - Sequelize Postgres - 如何使用 ON CONFLICT 来获得唯一性?

c - Typedef 结构指针正确指向 typedef 结构 (C)

c - fork 和线程有什么区别?

c# - 从文件到屏幕绘制骨骼动画

c# - 间接访问需要 volatile 吗?

c# - OutOfMemoryException,堆栈大小巨大,线程数量大

C# SSIS 脚本任务 - 格式化 Excel 列时添加千位分隔符