如何配置 MS SQL 服务器以避免更新锁定 (LCK_M_U)

How do I configure MS SQL server to avoid update lock (LCK_M_U)

我有 MS SQL 服务器,其数据库包含多个 table。每个 table 都有一个字段 'SN'。多个客户端可以使用此数据库,但每个客户端仅使用具有自己的 SN 值的记录进行操作。

一种客户端应用程序是使用 pyodbc 在 python 中编写的遗留软件。据我了解,该软件可以创建长事务——它可以执行 UPDATE 或 INSERT 语句并仅在几个小时后提交它们。我知道这样做是错误的,但修改那个软件是不可取的。

事务隔离级别设置为 READ_COMMITED,READ_COMMITTED_SNAPSHOT 设置为开启。

除以下情况外一切正常:

  1. 首先,遗留客户端启动更新记录及其 SN 值的事务,比如 SN = 1
  2. 另一个客户端应用程序尝试使用其 SN 值更新记录,比如 SN = 2

这种情况导致第二个客户端 LCK_M_U 锁定: ridlock field = 1 pageid = 311 dbid=5 id=lock2776cf380 mode=X associatedObjectId=...这里有很多数字...

虽然这两个客户端使用不同的 SN 值,但这会导致锁定。我怀疑发生这种情况是因为 SQL 服务器锁定的不是特定的行,而是页面(我猜是行的集合)。

根据 SO 问题 (Is it possible to force row level locking in SQL Server?),由于锁升级,无法保证行锁。

我考虑过将事务隔离级别设置为 'READ UNCOMMITTED',但我不确定这是正确的方法。

有什么方法可以正确配置 MS SQL 服务器来解决此锁定并允许 'simultaneous' 更新不同的行?

SN 上分区可能是最好的方法。您可以使用另一种方法,但请谨慎使用。您可以通过启用跟踪标志 1211 来禁用锁定升级。但是,此跟踪标志会在 SQL 服务器实例中全局禁用所有锁定升级。锁升级在 SQL 服务器中非常有用,它可以最大限度地提高查询效率,否则这些查询会因获取和释放数千个锁的开销而减慢。锁升级还有助于最小化跟踪锁所需的内存。 SQL 服务器可以为锁结构动态分配的内存是有限的,因此如果禁用锁升级并且锁内存增长到足够大,尝试为任何查询分配额外的锁可能会失败。

我找到了一个似乎适合我的解决方案。它在 this topic on microsoft forum 中有描述。这个想法是为表中的 SN 字段创建索引,如下所示:

CREATE INDEX IX_SN ON TABLE_NAME(SN)