我有一个Sql查询,它返回超过50万行进行处理...这个过程不需要很长时间,但我希望通过一些多处理来加快它的速度。考虑下面的代码,可以轻松地多线程吗?
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// ...process row
}
}
如果我可以简单地在结果列表的开头和中间获得光标,那将是完美的。这样,我可以有两个线程处理记录。但是SqlDataReader不允许我这样做......
知道如何实现这一目标吗?
答案 0 :(得分:6)
设置一个生产者/消费者队列,其中一个生产者进程从读取器中拉出并尽可能快地排队记录,但不进行“处理”。然后,一些其他数量的进程(您想要多少进程取决于您的系统)将每个排队记录出列并处理。
答案 1 :(得分:3)
您不应该在客户端上阅读那么多行。
话虽这么说,您可以将查询分区为多个查询并并行执行。这意味着在单独的线程中启动多个SqlCommands,并让它们每个流失一个结果的分区。 A +问题是如何对结果进行分区,这主要取决于您的数据和查询:
ID betweem 1 and 10000
,ID between 10001 and 20000
等)RecordTypeID IN (1,2)
,RecordTypeID IN (3,4)
等)ROW_NUMBER() BETWEEN 1 and 1000
etC),但这对拉右是非常有问题的BINARY_CHECKSUM(*)%10 == 0
,BINARY_CHECKSUM(*)%10==1
等)您必须非常小心分区查询在执行期间不会重叠并且阻止(即扫描相同的记录并获取X锁),从而相互序列化。
答案 2 :(得分:-1)
是一个简单的远程查询,例如1到500000之间的WHERE Id吗?如果是这样,您可以启动N个查询,每个查询返回范围的1 / N.但通过单线程方法了解您的瓶颈有所帮助。如果您正在从一个磁盘主轴进行连续读取以完成查询,那么您应该坚持使用单个线程。如果它在某个范围内跨主轴分区,那么您可以智能地调整查询以最大化磁盘的吞吐量(即,从单独的查询并行读取每个磁盘)。如果您希望所有行都在内存中,那么您可以随意进行并行化。但是如果查询更复杂,那么您可能无法轻松地对其进行分区而不会产生大量开销。大多数情况下,上述选项不适用,Joel提到的生产者/消费者将是唯一并行化的地方。根据您处理每一行所花费的时间,这可能只会带来微不足道的收益。