sql-server - SQL Server 锁定的 DataReader 行为

标签 sql-server locking datareader

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

所以我想我有点天真的问题是,由于执行查询而被取出的锁在什么时候实际上被放弃了?我们似乎发现锁一直保留到 DataReader 的最后一行被处理并且 DataReader 实际上关闭 - 这看起来正确吗?快速了解 DataReader 如何在幕后工作会很棒,因为我一直在努力寻找有关它的任何像样的信息。

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

最佳答案

  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.Read 循环内读取业务对象时将其编码(marshal)回,这就是执行此操作的方法。预先读入内存然后进行编码可能会在大型数据集上增加更多问题。

关于sql-server - SQL Server 锁定的 DataReader 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1538661/

相关文章:

sql-server - 我们可以完全依赖数据库引擎优化顾问吗?

sql-server - 获取 child 的所有 parent

c# - 锁能开多深?

java - Java中全局锁的实现

c# - 将字符串分配给字符串变量抛出算术运算导致溢出,

c# - SQL 服务器,C# : Timeout exception on Transaction Rollback

sql - 如何在 MS SQL 中进行限制和排序?

mysql - 强制 MySQL 在另一个条件之前评估一个条件

python - pandas_datareader.data 不返回从开始日期到结束日期的所有股票值

c# - IDataReader - 有什么方法可以获取总行数?