C#使用多线程或并行执行执行SQL SP

C#使用多线程或并行执行执行SQL SP,c#,sql,.net,sql-server,multithreading,C#,Sql,.net,Sql Server,Multithreading,我有一个SQL Server SP,并希望为大约1000万个用户记录集执行该SP,以处理用户信息并更新数据库。目前,一个用户更新数据库需要几毫秒的时间。既然要处理数百万条记录,那么最好的方法是什么 我正在考虑使用多线程或并行foreach从C#应用程序中执行此操作。下面是运行SP的基本代码,如何使用它在多线程模式下运行它以更快地完成处理任务 string connString = "data source=.\SQLEXPRESS;initial catalog=Test;integrated

我有一个SQL Server SP,并希望为大约1000万个用户记录集执行该SP,以处理用户信息并更新数据库。目前,一个用户更新数据库需要几毫秒的时间。既然要处理数百万条记录,那么最好的方法是什么

我正在考虑使用多线程或并行foreach从C#应用程序中执行此操作。下面是运行SP的基本代码,如何使用它在多线程模式下运行它以更快地完成处理任务

 string connString = "data source=.\SQLEXPRESS;initial catalog=Test;integrated security=True;";
            SqlConnection conn = new SqlConnection(connString);
            conn.Open();
            SqlCommand cmd = new SqlCommand("ETL_TEST", conn);
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add(new SqlParameter("@user_id", '12345'));
            cmd.ExecuteReader();
            conn.Close();
如何使用它在多线程模式下运行它以更快地完成处理工作

 string connString = "data source=.\SQLEXPRESS;initial catalog=Test;integrated security=True;";
            SqlConnection conn = new SqlConnection(connString);
            conn.Open();
            SqlCommand cmd = new SqlCommand("ETL_TEST", conn);
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add(new SqlParameter("@user_id", '12345'));
            cmd.ExecuteReader();
            conn.Close();
Parallel.ForEach()是实现目标的一个非常合理的起点,向SQL Server发送并发请求可以提高总体吞吐量

将代码放入Parallel.ForEach()的操作中。用于确保正确地处理了这些内容(如果在关闭连接之前抛出异常,那么现在您将保持连接处于打开状态)

请注意,.NET Framework将尝试找到最佳线程数(不同版本的框架可能最终选择不同的线程数)。NET可能会选择多个线程,这些线程是

  • 太低(您无法影响,但可以通过显式创建和管理任务来解决)
  • 过高,导致SQL Server执行效率低下(由于IO或锁争用、高CPU等)。在这种情况下,可以使用该属性限制线程数。如果移动到功能或多或少的SQL Server,请不要忘记调整属性
请注意,多线程解决方案虽然可能比单线程解决方案更有效,但仍然非常健谈。它为每个用户记录向数据库发出请求。在这种情况下,我通过向SQL Server发送一批工作而不是单个工作项,实现了数量级的性能改进。通过重新设计存储过程以同时接受多个用户,您可能会看到最大的收益

既然要处理数百万条记录,那么最好的方法是什么

如果你问什么是使过程并行的最佳方法,@Eric的答案看起来很有希望。我同意,一般来说,“在某种程度上,向SQL Server发送并发请求可以提高总体吞吐量”,只要我们真正强调“在某种程度上”这一部分。但是“那一点”很可能只是一次运行几次(取决于逻辑和模式),这不是您想要的收益类型


如果您想问,尽可能快/高效地完成1000万“集”记录处理的最佳方法是什么,那么这是一个更复杂的问题。这需要更多的分析。至少需要检查
ETL\u测试中的逻辑和模式(表、索引等)。因此,目前,这里没有足够的信息来提供这些方面有意义的帮助。

有几种方法可以加快速度:

  • 在表值参数中传递数据,这样您就可以在一次调用中处理它们,这可能是最好的方法,但它确实需要一些设置,而且如果这是一次性的,就不值得了
  • 因为您只处理一个参数,所以将其转换为逗号分隔的值字符串并传入,这样您就可以在服务器上处理每次调用的几千个参数
  • 在不改变太多代码的情况下,您可以做的最简单的事情就是将其放在事务中,并每数千条记录提交一次记录,或者一次提交所有记录。这样做将使速度提高约100倍

  • 多线程最终会慢很多。实际上,您必须将其更改为逐行。或者此进程已经在逐行执行此操作了?还有一个SP被写入以执行逐行操作,这需要很多时间。@SeanLange:不,不会慢很多。在某种程度上,对SQL Server的多个并发请求加快了总体吞吐量。您试图更新哪些用户信息,如列、数据类型?另外,更新信息来自哪里?需要强调的是,TPL通常会完全偏离IO工作的最佳线程数。随着时间的推移,线程的数量(字面上)将趋于无穷大。这很容易通过
    睡眠(100)
    重现+1因为你这么说了,但我想更强调这一点。@usr:根据我的经验,TPL在选择线程数量方面做得很合理,但并不完美。在做与相关问题相关的工作时,我确实必须明确限制平行度。你能举一个例子说明TPL何时会倾向于大量线程吗?我很想了解这种情况。真糟糕。在所有现实IO场景中都可以无限创建线程。该链接抱怨当工作负载配置文件急剧变化时,core创建新线程的速度太慢。它没有提到会创建任意数量的线程。引用:
    内存使用与线程数量成正比(此处为731)。
    。这两个问题都存在。缓慢增长但无限增长。那幅画太吓人了!线程数随时间的线性增长。在一夜之间推断出这一点。这就是导致生产系统瘫痪的问题。