2016-02-15 45 views
0

我的客户越来越这两个语句之间的经常性僵局:SQL服务器Pagelock死锁 - 插入和删除

DELETE b 
FROM employees a WITH (NOLOCK), employees_prs b WITH (NOLOCK) 
WHERE a.employer_id = @id 
    AND a.id = b.employee_id 
    AND b.employee_prs = 1 

INSERT INTO employees_prs (employee_id, employee_prs) 
SELECT DISTINCT a.id, 1 
FROM #tempdata01 b, employees a WITH (NOLOCK) 
WHERE a.employer_id = @id 
    AND a.no_id = b.no_id 

死锁图中的资源列表显示了这一点:

<resource-list> 
    <pagelock fileid="4" pageid="28897262" dbid="14" objectname="db01.dbo.employees_prs" id="lock373f60880" mode="IX" associatedObjectId="72057601182466048"> 
    <owner-list> 
    <owner id="process352a02988_INSERT" mode="IX" /> 
    </owner-list> 
    <waiter-list> 
    <waiter id="process11e0a1b88_DELETE" mode="U" requestType="wait" /> 
    </waiter-list> 
    </pagelock> 
    <pagelock fileid="4" pageid="25066463" dbid="14" objectname="db01.dbo.employees_prs" id="lock61081f580" mode="U" associatedObjectId="72057601182466048"> 
    <owner-list> 
    <owner id="process11e0a1b88_DELETE" mode="U" /> 
    </owner-list> 
    <waiter-list> 
    <waiter id="process352a02988_INSERT" mode="IX" requestType="wait" /> 
    </waiter-list> 
    </pagelock> 
    </resource-list> 

我觉得DELETE语句在页面上具有U锁,但也等待在另一个页面上获取另一个U锁。同样,INSERT语句在页面上有一个IX锁,并持续等待在另一页上获取另一个IX锁。 这是正确的吗?

我该如何解决死锁问题?

Table's结构:

CREATE TABLE [dbo].[employees](
    [id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 
    [employer] [int] NOT NULL, 
    [name] [varchar](30) NULL, 
CONSTRAINT [employees_PK] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
) 
) 


CREATE TABLE [dbo].[employees_prs](
    [employee_id] [int] NOT NULL, 
    [employee_prs] [tinyint] NOT NULL, 
CONSTRAINT [PK_employees_prs] PRIMARY KEY CLUSTERED 
(
    [employee_id] ASC, 
    [employee_prs] ASC 
) 
) 
+0

你应该做的第一件事就是停止使用NOLOCK提示丢弃你的数据库。这不是一个快速按钮。事实上,由于您正在使用删除操作,您可能会损坏索引。谢天谢地,这个提示将来会被禁止。 http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere/你也应该考虑使用更多的“当前”ANSI-92风格的连接。 http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old-style-joins.aspx –

+1

按顺序一次获取锁的声明,直到足够的锁使表可以安全地更改。我不确定,但看起来应该可以在delete语句中交换表,以便插入和删除两者都从锁定employees_prs开始。第一个这样做会阻止另一个持续锁定收购,直到收购完成。 – Lukos

+0

我确定这些表格之间没有FK吗?你应该删除'NOLOCK's。另外你没有以'employee_prs'开头的索引。这意味着你的'delete'语句需要扫描两个表。 –

回答

-1

获取锁一处,一时间在声明(S)的顺序,直到足够的锁定使得表(一个或多个)安全改变。我不确定,但看起来应该可以在delete语句中交换表,以便插入和删除两者都从锁定employees_prs开始。第一个这样做会阻止另一个持续锁定收购,直到收购完成。

+0

你对陈述顺序绝对正确,但你错过了一件事 - '删除'是一个单一的陈述。 –

+0

显示的delete语句在源数据中使用连接 - 它不是一个语句,但可以在两个表上导致锁定。 – Lukos

+0

这是一个_statement_。无论它包含什么以及锁定了多少个对象。 –