SQL Server锁定的DataReader行为
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server锁定的DataReader行为相关的知识,希望对你有一定的参考价值。
当通过DataReader
从SQL服务器查询返回大型数据集时,我们的数据层存在一些问题。当我们使用DataReader
来填充业务对象并将它们序列化回客户端时,获取可能需要几分钟(我们向用户显示进度:-)),但是我们发现有一些非常强硬的锁定进行on受影响的表,导致其他更新被阻止。
所以我想我的稍微天真的问题是,由于执行查询而被取出的锁实际上放弃了什么?我们似乎发现锁定仍然存在,直到DataReader
的最后一行被处理并且DataReader
实际上已经关闭 - 这看起来是否正确?关于DataReader
如何在幕后工作的快速101将是伟大的,因为我努力寻找任何体面的信息。
我应该说,我意识到锁定问题是主要问题,但我只是关注DataReader
的行为。
- 在执行查询期间,如果网络缓冲区已满,SQL Server可以暂停查询。如果客户端无法跟上网络的读取,即会发生这种情况。它不会调用SqlDataReader.Read()。释放网络缓冲区时恢复SQL Server查询,即。当客户端恢复SqlDataReader.Read()时。这意味着当您从数据读取器读取数据集结果时,查询仍在服务器上执行。有更多的细节,比如网络缓冲区的大小,客户端使用SqlBytes.Stream等的BLOB操作,但这个想法的要点是慢客户端可以导致查询被暂停,并且当客户端结束时查询结束。
- 在正常隔离级别(读取提交)下读取数据时,SQL Server将在其读取的行上放置短暂的共享锁。在更高的隔离级别下,锁是长寿命的,直到事务结束。
- 如果未使用任何事务,则每个SELECT语句将在语句的持续时间内创建隐式只读事务。
因此,从1,2和3我们可以看到,在高隔离级别下运行查询的慢客户端将导致共享锁保持很长时间。
现在你需要详细说明你观察的内容:
- 此查询持有什么类型的锁? S,U,X? 行,页面,表格? 范围锁?
- 锁升级是否发生?
- 为什么在查询期间保持锁定? 您是否使用REPEATABLE READ或SERIALIZATION隔离级别?如果有,为什么? 你使用锁提示吗?如果有,为什么?
您最好的选择可能是snapshot isolation(至少需要SQL Server 2005),可以是快照隔离级别,也可以是读取提交的快照。这将完全消除锁定问题,但会在tempdb上产生一些IO压力。
其他解决方案是使用游标,但是对现有代码库具有侵扰性,复杂且仍然容易出错(必须使光标类型正确)。
顺便说一句,我不建议更改客户端行为。我现在假设你在SqlDataReader循环中读取它们时正在编组业务对象,这就是这样做的方法。预先读入内存然后编组可能会在大型数据集上添加更多问题。
选择临时表会减少锁定持续时间
select blah from tbl into #temp << locks held and released
select * from #temp << take all the time you want now
以上是关于SQL Server锁定的DataReader行为的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server DataReader.GetField 返回 null 而不是地理数据
哪个版本的 Microsoft.SqlServer.Types.dll 解决了 SQL Server 2017 的“DataReader.GetFieldType 返回 null”错误?
MS Access 直通选择查询导致 SQL Server 中的页面锁定
在 ASP.Net 中使用 SQL Server 2012 地理数据类型 - DataReader.GetFieldType(x) 返回 null