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

时间:2010-07-27 15:44:21

标签: sql-server asynchronous

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

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

我们尝试了一些让连接处于SUSPENDED状态(由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();
 }

是否有人在强大的模式上有建议或链接来解决此类问题?

谢谢!

1 个答案:

答案 0 :(得分:4)

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

  • 您将很快被SQL Server中的max worker threads限制,并开始经历长时间连接Open次并经常超时。
  • 并行运行1000个负载比在N个连接上顺序运行1000个负载要慢得多,其中N由服务器上的核心数给出。成千上万的并行请求只会在共享资源上产生过多的争用,并相互减慢速度。
  • 在CLR中排队的数千个请求绝对没有可靠性。如果进程崩溃,您将失去所有工作 whitout any trace

更好的方法是使用一个队列,工作池从中加载并执行它们。典型的生产者 - 消费者。工作人员(消费者)的数量将由SQL Server资源(CPU核心,内存,负载的IO模式)调整,但安全数量是服务器核心数量的2倍。每个工作人员都使用专用连接进行工作。工作人员的角色和队列的作用不是为了加快工作,而是相反,它们充当限制机制,以防止您淹没服务器。

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

最后,您可以让SQL Server通过Activation处理所有内容,排队,限制和处理本身。请参阅Asynchronous Procedure Execution和后续文章Passing Parameters to a Background Procedure

哪一个是正确的解决方案取决于你对你的问题了解的很多因素,但我没有,所以我不推荐你应该走哪条路。