我从未尝试过这个 - 所以我不知道我是否会遇到内存问题。
但是 SqlDataReader 可以读取一万亿条记录吗?这一切都流式传输正确吗?我对 SQL/TDS 协议在幕后所做的事情有点陌生。
更新 将万亿翻译为非常大的数字。我可能应该说 10 亿或 1 亿。
我从未尝试过这个 - 所以我不知道我是否会遇到内存问题。
但是 SqlDataReader 可以读取一万亿条记录吗?这一切都流式传输正确吗?我对 SQL/TDS 协议在幕后所做的事情有点陌生。
更新 将万亿翻译为非常大的数字。我可能应该说 10 亿或 1 亿。
有几个细节。
SqlDataReader 通常会读取内存中的一整行并将其缓存。这包括任何 BLOB 字段,因此您最终可以在内存中缓存几个 2GB 字段(XML、VARBINARY(MAX)、VARCHAR(MAX)、NVARCHAR(MAX))。如果需要考虑此类字段,则必须将CommandBehavior.SequentialAccess传递给ExecuteReader并使用 SqlClient 特定类型(如SqlBytes.Stream )的流功能。
在 SqlDataReader 完成之前,连接一直处于忙碌状态。这会产生事务问题,因为您将无法在同一个事务中对数据库中的任何处理,因为连接很忙。尝试打开不同的连接并注册同一事务将失败,因为环回分布式事务被禁止。问题是使用MARS。MultipleActiveResultSets=True
您可以通过设置连接来做到这一点。这允许您在数据读取器仍处于活动状态时在同一连接上发出命令(典型的 fetch-process-fetch 循环)。仔细阅读 Christian Kleinerman 的链接,确保您了解 MARS 和交易的问题和限制,它们非常微妙且违反直觉。
客户端中的冗长处理将阻塞服务器。您的查询仍将一直执行,当通信管道填满时,服务器将不得不暂停它。一个查询消耗一个工人(如果它有并行计划,则消耗更多)并且工作是服务器中非常稀缺的商品(它们大致等同于线程)。您将无法负担许多客户在自己的闲暇时间处理大量结果集。
交易规模。在一次交易中处理一万亿条记录永远不会奏效。日志将不得不增长以容纳整个事务,并且不会截断和重用 VLF,从而导致巨大的日志增长。
恢复时间。如果在第 999 亿条记录处处理失败,它将不得不回滚所有已完成的工作,因此仅需要“12”天才能回滚。
是的,那会流...但我认为您实际上不应该尝试这样做。
如果您每秒可以读取一百万条记录(在我看来这听起来不太可能),您仍然需要 12 天才能读取一万亿条记录……这需要大量工作才能冒半途而废的风险。
现在我意识到你可能真的不想从字面上阅读一万亿条记录,但我的观点是,如果你无论如何都可以将“大量”工作分成逻辑批次,那可能是个好主意。
是的 - 这可能需要一段时间(只要您的 SQL 没有做任何愚蠢的事情来尝试拍摄快照或任何事情),但如果您的服务器可以将其流式传输,则 SqlDataReader 不应该有内存使用问题。