SQLDataReader如何处理真正大的查询?

Jef*_*ffR 10 c# sql

实际上我不确定标题是否准确描述了这个问题,但我希望它足够接近.

我有一些代码从数据库表执行SELECT,我知道这将导致大约150万行被选中.每行中的数据不大 - 每行可能20个字节.但这仍然是30MB的数据.每行包含一个客户编号,我需要为每个客户做一些事情.

我的代码看起来像:

SqlConnection conn = new SqlConnection(connString);
SqlCommand command = new SqlCommand("SELECT ... my select goes here", conn);
using (conn)
{
    conn.Open();
    using (SqlDataReader reader = command.ExecuteReader())
    {
        while(reader.Read())
        {
            ... process the customer number here
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我只是迭代SELECT返回的所有客户.

我的问题是,这会导致数据库的多次读取,还是只读取一次?我假设网络缓冲区不足以容纳30MB的数据,那么.NET在这里做什么呢?每次Read()推进指针时,SELECT的结果是否会让某些地方的SQLDataReader啃掉一行?还是回到数据库?

我问的原因是代码中的"...处理客户编号"部分可能需要一些时间,因此对于150万客户而言,代码(上面的while循环)将花费很多时间来完成.当发生这种情况时,我是否需要担心其他人在数据库上阻挡我,或者我知道我已经从数据库中完成了一个SELECT并且我不会再回来了吗?

Mic*_*een 8

选择将作为“单一的整体事务”执行。输出的余额缓存在 SQL Server 中,并在协议确定有缓冲区可用于接收它时传递到网络。不过,SQL Server 不会每次都返回到数据表中。原始数据SELECT经过它时的数据状态将返回到您的应用程序。如果您指定了 (NOLOCK),则不会对数据产生进一步影响。其他人可以读写;你不会看到他们的变化。但是,您还没有完成 SQL Server,直到最后一行在您的应用服务器的缓冲区中,几个小时后。每个“我现在有更多空间,请”都会有网络流量,但不会明显超过一次全部 30MB。

对于大型结果集和长时间运行的进程,您最好编写应用程序来批量处理数据,即使基础架构可以支持完整的查询输出。回答每个批处理查询所需的资源更少。在失败的情况下,您只需要处理剩余的行;您不必从头开始。您的应用程序最终将完成更多的工作,但每个块对环境的破坏性较小。


anb*_*buj 5

请求发送一次,而不是每次您的读者前进时。然后结果将根据大小由多个结果集发送回客户端。

默认结果集是将结果传输到客户端的最有效方式。从客户端计算机发送到服务器的唯一数据包是带有要执行的语句的原始数据包。当结果发送回客户端时,SQL Server 将尽可能多的结果集行放入每个数据包中,从而最大限度地减少发送到客户端的数据包数量。

参考http://msdn.microsoft.com/en-us/library/ms187602.aspx

提交请求以供执行时,SQL Server 通过以下方式将结果集发送回客户端:

  1. SQL Server 接收来自客户端的网络数据包,其中包含要执行的 Transact-SQL 语句或一批 Transact-SQL 语句。
  2. SQL Server 编译并执行语句或批处理。
  3. SQL Server 开始将结果集的行或批处理或存储过程中的多个结果集放入网络数据包中,并将它们发送到客户端。SQL Server 在每个数据包中放置尽可能多的结果集行。
  4. 包含结果集行的数据包缓存在客户端的网络缓冲区中。当客户端应用程序获取行时,ODBC 驱动程序或 OLE DB 提供程序从网络缓冲区中提取行并将数据传输到客户端应用程序。客户端以向前的方式一次检索一行结果。

默认结果集不会在一个大块中提供给应用程序。结果集缓存在客户端的网络缓冲区中。应用程序一次通过结果集获取一行。在每次提取时,OLE DB 提供程序或 ODBC 驱动程序将网络缓冲区中下一行的数据移动到应用程序中的变量中。OLE DB、ODBC 和 ADO 应用程序使用相同的 API 函数来检索行,它们将用于从游标中获取行。SqlClient 托管提供程序使用 SqlDataReader 类来公开默认结果集。当 MultipleActiveResultSets 设置为 true 时,允许在给定时间打开多个 SqlDataReader。

参考:http : //technet.microsoft.com/en-us/library/ms187602(v=sql.105).aspx


Sch*_*ere 1

首先,我将把您重定向到以下关于SO的问题,其中描述了如何处理锁等:

了解 SELECT 查询上的 SQL Server 锁

我的第一个问题是,您将运行此查询多少次。如果是每日数量,请确保选择数据库上使用的用户数量最少的时间。

第二个问题是,你打算如何处理这些数据?也许您应该记住,当处理 1M+ 记录时,存储过程会更快,因为它会处理数据库上的所有内容并保持较低的流量。