【问题标题】:Select query blocking database table选择查询阻塞数据库表
【发布时间】:2021-05-11 08:01:00
【问题描述】:

我们的生产设置是我们有一个应用程序服务器,其中的应用程序连接到 SQL Server 2016 数据库。在应用服务器上,有几个 IIS 应用程序在 GMSA 帐户下运行。 GMSA 帐户对数据库具有 db_datawriter 和 db_datareader 权限。

我们的团队在同一个 SQL Server 数据库上拥有 db_datareader 权限。我们需要它用于生产支持目的。

我们最近发生了一起事件,团队成员在其本地计算机上调用 SQL Server Management Studio 上的查询:

SELECT * FROM [DatabaseA].[dbo].[TableA] order by CreateDt desc;

TableA有大约 140 万条记录,并且有多个 blob 类型的列。 CreateDtDATETIME2 类型的列。

我们为 SQL Server 数据库服务器配置了 RedGate SQL Monitor。这引发了一个运行了 1738 秒的长时间运行的查询警报。

同时,我们的一个专门向TableA 插入新记录的 Web 应用程序 (.NET 4.6) 经常遇到查询超时错误:

Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

这些错误发生在几乎完全相同的 1738 秒期间。这让我相信这些是相互关联的。

我的理解是SELECT 查询只会创建一个共享锁,不会阻止另一个连接对该表的访问。我的理解是否正确?

我的问题是 db_datareader 对团队成员安全吗?是否存在允许读取数据但绝对无法创建阻止行为的较小权限。

【问题讨论】:

  • 这能回答你的问题吗? Understanding SQL Server LOCKS on SELECT queries
  • This leads me to believe these are connected. 连接并完整记录,数百篇文章、课程、书籍解释了它发生的原因以及如何避免这种情况。它从 not 无故查询 1M 行开始。当你读取整个表时,锁会升级到表本身级别,阻塞修改。你想做什么?如果您真的需要读取所有这些行,则可以使用 SNAPSHOT 隔离。这有其自身的成本,因为修改行的版本被复制到tempdb,直到读取事务完成。更好的设计可能更快、更便宜
  • 好的,我知道这些肯定是有关联的。答案似乎表明开发人员应该编写他们的查询是避免这种情况的一种特殊方式,这很好。但是,这并不能阻止这种情况的发生(例如意外),是否存在使这种情况变得不可能的特权级别?
  • 检查Resolve blocking problems caused by lock escalation in SQL Server 了解为什么锁会升级到页面或表级别以及如何避免这种情况。无论如何,这不是关于特权,而是关于设计。将同一张表用于运营和报告目的是个坏主意,因为报告会读取大量数据,会阻止修改
  • @Ben to prevent this 不要在生产环境中运行临时查询。不要无缘无故给别人datareader。如果人们需要实验或报告,克隆或复制数据。 SQL Server 中的备份操作是在线的,即它们不会阻止应用程序。您可以根据需要进行备份并在不同的服务器上恢复它们​​。在该服务器上给开发人员datareader,而不是生产数据库

标签: c# sql .net sql-server


【解决方案1】:

查询中存在 SELECT * (SELECT STAR),通常会导致不使用索引并对表进行 SCAN。 对于许多 LOB(BLOB 或 CLOBS 或 NCLOB)和许多行,order by 子句将需要很长时间:

  1. 生成条目
  2. 对 CreateDt 进行排序

所以在读取表的所有数据的时候,放了一个读锁(共享锁)。此锁接受其他共享锁,但禁止放置排他锁来修改数据(INSERT、UPDATE、DELETE)。这可以向其他用户保证数据不会被修改。

这种锁定技术被称为悲观锁定。在开始执行查询之前获取锁,并在最后放松。所以 reader 会阻止 writer, writers 会阻止所有。

SQL Server 可以做的另一种技术,称为乐观锁定,包括使用数据的副本,没有任何锁定,并在执行结束时验证写入所涉及的数据从一开始就没有被修改.所以阻塞少了……

要进行悲观锁定,您可以选择允许或强制:

ALTER DATABASE CURRENT SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE CURRENT SET READ_COMMITTED_SNAPSHOT ON;

【讨论】:

    【解决方案2】:

    在 SQL Server 中,写入者阻止读取者,而读取者阻止写入者。 此查询没有 where 子句,将触及整个表,可能从 IS(意图共享)开始,最终升级为共享锁,当锁存在时更新/插入/删除无法访问。这很可能是在很长的排序期间举行的,由顺序引起。

    可以通过多种方式绕过它,但我不认为您实际上是在追求如何,因为运行查询的人可能并没有真正考虑清楚,而且这种情况并不常见。 不过,这里有一些绕过的方法:

    1. 读取提交的快照隔离
    2. 带(无锁)。但前提是您并不真正关心检索到的数据,因为它可以返回两次行、从未提交的行并完全跳过行。
    3. 减少您返回的列并改为从非聚集索引中读取。

    但要回答您的问题,是的,选择可以阻止插入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多