避免并发删除死锁
Posted
技术标签:
【中文标题】避免并发删除死锁【英文标题】:Avoid deadlock for concurrent delete 【发布时间】:2013-02-25 18:12:44 【问题描述】:我有一个名为Products
的表,其中包含许多列。它是用于报告目的的临时表。多个用户请求将同时处理数据到该表。有单独的存储过程可以对该表进行 DML 操作。
表结构:
CREATE TABLE Products (
instance uniqueidentifier,
inserted datetime,
col1,
col2,
...
)
inserted
列将填充 GETDATE()
以包含插入每一行的时间,instance
列将包含来自 newid()
的值。一个用户请求将有一个唯一的 id,但可能有数百万行。以下是将并发执行的查询,这会导致死锁。请指教
查询 1:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DELETE P
FROM Products (NOLOCK)
WHERE instance = 'XXXX-xxx-xxx-xx'
查询 2:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DELETE P
FROM Products (NOLOCK)
WHERE inserted <= DATEADD(hh, -10, GETDATE())
注意:非聚集索引是在实例列上创建的。
请告诉我在这种情况下我可以使用哪种锁。
请注意,当我向表中插入 1000 万行时,我无法主键,因为它会消耗时间(这是一个事务;有 20 个并发事务)。
报告应尽快生成。我的程序有多个 35 个 DML 语句,大约有 15 个 DELETE 语句,例如带有其他列的实例列(DELETE FROM table WHERE instance = @instance AND col1 = @col1
)。
【问题讨论】:
看看这个***.com/questions/9952137/… 【参考方案1】:(1) 您应该停止使用read uncommitted
隔离。至少使用read committed
。
(2) 您可以尝试多种方法来避免死锁,例如确保您的不同事务以相同的顺序访问数据库对象等。这值得一读 - http://support.microsoft.com/kb/169960
(3) 为您的表禁用锁升级(更精细的锁因此更好的并发性,但更多的锁开销):
ALTER TABLE Products SET (lock_escalation = disable)
(4) 禁止页面锁定,并允许对索引进行行锁定(这意味着您不能对索引进行碎片整理,但您仍然可以重建它们):
ALTER INDEX [<YourIndex>] ON Product WITH (allow_row_locks = on, allow_page_locks = off)
【讨论】:
【参考方案2】:首先,除了独占锁之外,您无法对这些删除语句使用任何锁。你的isolation level and NOLOCK
hints are being ignored by Sql Server:
(Nolock) 仅适用于
SELECT
语句。
两个建议:
将instance
上的非聚集索引更改为聚集索引。但是,只有在您可以将 NEWID()
更改为 NEWSEQUENTIALID()
时才这样做。
其次,不要执行delete
来删除超过 10 小时的记录...考虑implementing rolling partitions。这将消除因清理与您的其他 delete
操作引起的任何争用。
【讨论】:
以上是关于避免并发删除死锁的主要内容,如果未能解决你的问题,请参考以下文章