我们在包含订单履行的交易表中使用聚簇列存储索引。此表由不同的会话定期更新。但是,每个会话都特定于订单作业编号,因此,他们不会尝试同时更新同一行。但是,由于以下会话之间的情况,我们正面临死锁问题。
这不是特定于存储过程的。这是由于多个存储过程一个接一个地顺序更新此表,作为订单履行的一部分。
表的示例模式非常简单:
CREATE TABLE OrderFulfillments
(
OrderJobNumber INT NOT NULL,
FulfilledIndividualID BIGINT NOT NULL,
IsIndividualSuppressed BIT NOT NULL,
SuppressionReason VARCHAR(100) NULL
)
我已经提供了示例死锁图供您参考。请让我知道,我可以采取什么方法来避免这种僵局。我们需要在此表中使用聚簇Columnstore索引,因为我们正在进行聚合操作以查看已经完成了个人的次数。没有列存储索引,它可能会更慢。
答案 0 :(得分:1)
您认为NOLOCK与没有锁定相同......这是不正确的。
NOLOCK相当于READUNCOMMITTED。
•READUNCOMMITTED和NOLOCK提示仅适用于数据锁。
所有查询,包括具有READUNCOMMITTED和NOLOCK提示的查询, 在编译期间获取Sch-S(模式稳定性)锁定 执行即可。因此,在并发时会阻止查询 事务在表上持有Sch-M(模式修改)锁。
例如,数据定义语言(DDL)操作获取Sch-M 在它修改表的架构信息之前锁定。
任何并发查询,包括使用READUNCOMMITTED或 NOLOCK提示,在尝试获取Sch-S锁时被阻止。 相反,持有Sch-S锁的查询会阻止并发 试图获得Sch-M锁的交易。
无法为修改的表指定READUNCOMMITTED和NOLOCK 插入,更新或删除操作。 SQL Server查询优化器 忽略FROM子句中的READUNCOMMITTED和NOLOCK提示 应用于UPDATE或DELETE语句的目标表。
您可以在保护事务的同时最大限度地减少锁定争用 使用以下任一方法对未提交的数据修改进行脏读 以下:
•READ COMMITTED隔离级别 READ_COMMITTED_SNAPSHOT数据库选项设置为ON。
•SNAPSHOT 隔离级别。有关隔离级别的更多信息,请参阅SET TRANSACTION ISOLATION LEVEL(Transact-SQL)。
https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table
了解您的索引的结构如何导致阻塞,如果说,select语句需要您的UPDATE同时修改的整个页面。
在测试时限制您的变量。
考虑将DML拆分为多个部分。您可以找到执行表数据并发修改的最佳范围。
答案 1 :(得分:1)
在我的情况下,死锁情况是由于锁定升级发生,因为一些执行非常大并且在10,000s或100k范围内并且导致锁升级发生在行组级别,在某些情况下,页面水平。
我通过在事务开始时使用临时表并处理临时表上的更新并最终将临时表相关的实现信息插入到此OrderFulfillments
中来解决此问题。临时表也使用此OrderFulfillments
来查看已完成个人的次数。但是,它是顶部的共享锁而不是独占锁。
通过访问临时表,每个会话都在处理自己的副本并解决并发问题。