ADO.NET异步读取器(队列处理)

lon*_*day 0 sql-server oracle ado.net

我有一个大表,1B +记录,我需要下拉并在每条记录上运行算法.如何使用ADO.NET异步执行"select*from table"并在ado.net接收数据时逐个读取行?

我还需要在读取它们之后处理这些记录以节省内存.因此,我正在寻找一种方法来按记录拉下记录表,并基本上将记录推入队列进行处理.

我的数据源是oracle和mssql.我必须为几个数据源执行此操作.

Rem*_*anu 8

您应该使用SSIS.

您需要了解ADO.Net数据提供程序如何工作以了解您可以执行的操作以及不能执行的操作的背景细节.让我们以SqlClient提供商为例.确实可以异步执行查询,BeginExecuteReader但这种异步执行只有在查询开始返回结果之后才会执行.在线级,SQL文本被发送到服务器,服务器开始搅拌查询执行,最终将开始将结果行推回客户端.只要第一个数据包返回到客户端,就会完成异步执行并执行完成回调.之后,客户端使用该方法来推进结果集.SqlDataReader中没有异步方法.这种模式对于在完成一些严肃处理后返回很少结果的复杂查询起了作用.当服务器忙于产生结果时,客户端处于空闲状态而没有阻塞线程.然而,对于生成大型结果集的简单查询(就像您的情况一样),情况完全不同:服务器将立即生成resutl并将继续将它们推回客户端.异步回调几乎是不稳定的,并且大部分时间将由客户端在SqlDataReader上进行迭代.SqlDataReader.Read()

您说您正在考虑首先将记录放入内存队列中.队列的目的是什么?如果算法处理速度低于DataReader结果集迭代的吞吐量,则此队列将开始构建.它会消耗实时内存,最终会耗尽客户端的内存.为了防止这种情况,你必须建立一个流量控制机制,即.如果队列大小大于N,则不再添加任何记录.但要实现这一点,您必须暂停数据读取器迭代,如果这样做,则将流控制推送到服务器,该服务器将暂停查询,直到通信管道再次可用(直到您开始从读取器读取).最终,流量控制必须一直延伸到服务器,在任何生产者 - 消费者关系中总是如此,生产者必须停止否则中间队列填满.除了使事情复杂化之外,你的内存中队列完全没有用处.您可以逐个处理读取器中的项目,如果处理速度太慢,数据读取器将导致流控制应用于服务器上运行的查询.这只是因为您没有调用DataReader.Read方法而自动发生.

总而言之,对于大型集合处理,您无法进行异步处理,也不需要队列.

现在困难的部分.

您的处理是否在数据库中进行任何类型的更新?如果是,那么你有更大的问题:

  • 您不能使用相同的连接来回写结果,因为它正忙于数据读取器.SQL Server的SqlClient支持MARS,但只能解决SQL 2005/2008的问题.
  • 如果您要在事务中注册读取和更新,如果您的更新发生在不同的连接上(参见上文),那么这意味着使用分布式事务(即使涉及的两个conencitons指向同一服务器).分布式事务很慢.
  • 您需要将处理拆分为多个批次,因为在单个事务中处理1B +记录非常糟糕.这也意味着您必须能够继续处理已中止的批处理,这意味着您必须能够识别已处理的记录(除非处理是幂等的).