C# 用于更新数据库的多线程应用程序

C# 用于更新数据库的多线程应用程序,c#,multithreading,thread-safety,database-update,C#,Multithreading,Thread Safety,Database Update,我有一个C#应用程序,它将行插入SQL Server数据库中三个单独的表中。这是一个大规模的批处理作业(每个批处理2-3M+行)。我的代码如下所示(我已编辑以删除不必要的细节): 这个过程是离线的,我想让尽可能多的工作与数据库一起排队,以提高吞吐量。我的问题是,是否有一个最佳的线程数(或者是否有一种方法可以发现这可能是什么-除了尝试和错误)?另外,在使用线程执行类似操作时,是否有一个主要的注意事项需要警惕?除非您要进行大量处理,否则我猜您的瓶颈将是磁盘本身(数据库)。因此,线程的最佳数量可能是一

我有一个C#应用程序,它将行插入SQL Server数据库中三个单独的表中。这是一个大规模的批处理作业(每个批处理2-3M+行)。我的代码如下所示(我已编辑以删除不必要的细节):


这个过程是离线的,我想让尽可能多的工作与数据库一起排队,以提高吞吐量。我的问题是,是否有一个最佳的线程数(或者是否有一种方法可以发现这可能是什么-除了尝试和错误)?另外,在使用线程执行类似操作时,是否有一个主要的注意事项需要警惕?

除非您要进行大量处理,否则我猜您的瓶颈将是磁盘本身(数据库)。因此,线程的最佳数量可能是一个


当然,在应用程序可能正在运行时(如果是应用程序),您必须与希望退出该应用程序的人打交道,因此您需要某种退出检查才能及时关闭。

多线程应用程序只能在多核机器上更快地处理


如果数据库是瓶颈,而且很可能是,添加线程会减慢进程,因为除了线程间任务切换的开销外,数据库还将花费更多的时间排队和管理来自多个请求的工作。

好吧,我想你可以尝试某种连接池,这样,对于每个新用户(调用一些db事务),您将获得一个新线程(我称之为DBBrockers),这将使他能够访问数据库。要让所有这些都起作用,你需要一台多核机器;处理器越多,线程就越多

你需要进行实验。如果您对单个源进行读写,那么最佳线程数可能是一个。如果您从多个源读取数据,并向单个源写入数据,那么2或3可能会获得一些改进


在上面的例子中,最重要的胜利是从事务性插入切换到
SqkBulkCopy

不幸的是,试错是您最好的选择。由于这里需要考虑很多因素,所以很难预先预测一个精确的优化设计。您的更新数据来自哪里?如果它们来自共享资源,那么多线程可能没有多大帮助。此外,桌子的设计也发挥了作用。SQL Server是一个复杂的数据库,此批处理更新不一定是I/O绑定的。网络通信也可以在这里发挥作用,SQL Server配置也是如此

要获得最佳线程数,请在此处再次尝试并出错。我会从两个开始,然后尝试增加这个数字,甚至超过你拥有的核心数。这是因为您的客户机和服务器之间可能有一个网络。此外,每个线程都应该保持自己的数据库连接

作为客户端处理的替代方法,您可以将整个批处理作业输入文件(或您拥有的任何文件)上载到服务器,可能使用WCF。然后,您可以使用更好的机制来执行批处理更新,而不是单独的SQL命令


总是“测试和测量”。

这三个查询在我看来就像一个事务。如果一个线程出现故障,您可能不希望使事务成为多线程。除非您更改线程的优先级,这将增加单个核心上的吞吐量。我不认为这个地址是OPs的问题-他们特别说这是一个大批量作业,那么对新用户的引用如何相关?
string sqlCust = "INSERT INTO customer (account, name, last_order) VALUES (@account, @name, @last_order)";
string sqlOrder = "INSERT INTO orders (num, order_date) VALUES (@num, @order_date)"
string sqlOrderLines = "INSERT INTO order_lines (product) VALUES (@prod)"

db.Open();

while (GetNextCust())
{
    using (SqlCommand cmdIns = new SqlCommand(sqlCust, db.Connection))
    {
        cmdIns.Parameters.Add("@account", custAcc);
        cmdIns.Parameters.Add("@name", custName);
        cmdIns.Parameters.Add("@last_order", lastOrder);
        cmdIns.ExecuteNonQuery();
    }

    while (GetNextOrder(custAcc))
    {
         ...

         while (GetNextOrderLine(orderNum)
         {
             ...
         }
    }
}