如何异步调度数千个 SQL 请求

Jef*_*ang 1 sql-server asynchronous

我们正在编写一个简单的应用程序:

  • 构建数千条 SQL select 语句
  • 使用 BeginExecuteReader 运行每个选择
  • 将结果存入另一个数据库

我们尝试了一些方法,要么使连接处于挂起状态(由 sp_who2 验证),要么花费比 SQL 查询本身更长的时间来完成(可能是某种死锁?)。

我们是:

  • 在回调处理程序中调用 EndExecuteReader。
  • 调用 conn.Close() 和 conn.Dispose()
  • 递归地开始另一个调用

public static void StartQuery() {
  // build the query for array[i]
  // ...
  SqlConnection conn = new SqlConnection(AsyncConnectionString);
  conn.Open();
  cmd.BeginExecuteReader(CallbackHandler, cmd);

  i++;
}



public static void CallbackHandler(IAsyncResult ar) {
     // unpack the cmd
     cmd.EndExecuteReader();

     // read some stuff to a DataTable...

     // SqlBulkCopy to another database (synchronously)

     cmd.Connection.Close();
     cmd.Connection.Dispose();

     StartQuery();
 }
Run Code Online (Sandbox Code Playgroud)

有没有人有解决此类问题的可靠模式的建议或链接?

谢谢!

Rem*_*anu 5

AsyncronousProcessing我假设您确实在连接字符串上设置了。CLR 中汇集的数千个 BeginExecute 查询会导致灾难:

  • 您将很快受到max worker threadsSQL Server 中的限制,并开始经历较长的连接Open时间和频繁的超时。
  • 并行运行 1000 个负载肯定比在 N 个连接上顺序运行 1000 个负载慢得多,其中 N 由服务器上的核心数量给出。数以千计的并行请求只会造成共享资源的过度争用并互相减慢速度。
  • 在 CLR 中排队的数千个请求绝对没有可靠性。如果进程崩溃,您将失去所有工作,不留任何痕迹

更好的方法是使用一个队列,工作池从中出队加载并执行它们。典型的生产者-消费者。工作线程(消费者)的数量将根据 SQL Server 资源(CPU 核心、内存、负载 IO 模式)进行调整,但安全数量是服务器核心数量的 2 倍。每个工作人员都使用专用连接来完成其工作。工作线程和队列的作用并不是加快工作速度,相反,它们充当了一种节流机制,防止你淹没服务器。

更好的方法是将队列保留在数据库中,作为从崩溃中恢复的一种方法。请参阅使用表作为队列了解正确的方法,因为基于表的队列非常容易出错。

最后,您可以让 SQL Server 通过Activation处理所有事情,包括排队、限制和处理本身。请参阅异步过程执行和后续文章将参数传递给后台过程

哪一种是正确的解决方案取决于您对问题了解的很多因素,但我不知道,所以我不能建议您应该走哪条路。