SQL Server锁定的DataReader行为

Gra*_*ham 4 sql-server locking datareader

当通过SQL从SQL服务器查询返回大型数据集时,我们的数据层存在一些问题DataReader.当我们使用DataReader填充业务对象并将它们序列化回客户端时,提取可能需要几分钟(我们向用户显示进度:-)),但我们发现有一些相当硬核锁定正在进行在受影响的表上导致其他更新被阻止.

所以我想我的稍微天真的问题是,由于执行查询而被取出的锁实际上放弃了什么?我们似乎发现锁一直存在,直到最后一行DataReader被处理并且DataReader实际上已经关闭 - 这看起来是否正确?快速了解DataReader幕后工作将如何很好,因为我一直在努力寻找任何体面的信息.

我应该说,我意识到锁定问题是主要问题,但我只关心DataReader这里的行为.

Rem*_*anu 11

  1. 在执行查询期间,如果网络缓冲区已满,SQL Server可以暂停查询.如果客户端无法跟上网络的读取,即会发生这种情况.它不会调用SqlDataReader.Read().释放网络缓冲区时恢复SQL Server查询,即.当客户端恢复SqlDataReader.Read()时.这意味着当您从数据读取器读取数据集结果时,查询仍在服务器上执行.有更多的细节,比如网络缓冲区的大小,客户端使用SqlBytes.Stream等的BLOB操作,但这个想法的要点是慢客户端可以导致查询被暂停,并且当客户端结束时查询结束.

  2. 在正常隔离级别(读取提交)下读取数据时,SQL Server将在其读取的行上放置短暂的共享锁.在更高的隔离级别下,锁是长期存在的,直到事务结束.

  3. 如果未使用任何事务,则每个SELECT语句将在语句的持续时间内创建隐式只读转换.

因此,从1,2和3我们可以看到,在高隔离级别下运行查询的慢客户端将导致共享锁保持很长时间.

现在你需要详细说明你观察的内容:

  • 此查询持有什么类型的锁?
    • S,U,X?
    • 行,页面,表格?
    • 范围锁?
  • 锁升级是否发生?
  • 为什么在查询期间保持锁定?
    • 您是否使用REPEATABLE READ或SERIALIZATION隔离级别?如果有,为什么?
    • 你使用锁提示吗?如果有,为什么?

您最好的选择可能是快照隔离(至少需要SQL Server 2005),可以是快照隔离级别,也可以是读取提交的快照.这将完全消除锁定问题,但会在tempdb上产生一些IO压力.

其他解决方案是使用游标,但是在现有的代码库上是复杂的,复杂的,并且仍然容易出错(必须使光标类型正确).

顺便说一句,我建议更改客户端行为.我现在假设你在SqlDataReader循环中读取它们时正在编组业务对象,这就是这样做的方法.预先读入内存然后编组可能会在大型数据集上添加更多问题.