SQL Server锁定的DataReader行为

问题描述 投票:4回答:2

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

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

我应该说,我意识到锁定问题是主要问题,但我只是关注DataReader的行为。

sql-server locking datareader
2个回答
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隔离级别?如果有,为什么? 你使用锁提示吗?如果有,为什么?

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

其他解决方案是使用游标,但是对现有代码库具有侵扰性,复杂且仍然容易出错(必须使光标类型正确)。

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


1
投票

选择临时表会减少锁定持续时间

select blah from tbl into #temp << locks held and released

select * from #temp << take all the time you want now
© www.soinside.com 2019 - 2024. All rights reserved.