如何避免这两个 SQL 语句之间出现死锁?

发布于 2024-09-06 14:29:22 字数 6086 浏览 13 评论 0原文

我有两个存储过程在单独的线程中运行,在 SQL Server 2005 上运行。一个过程将新行插入到一组表中,另一个过程从同一组表中删除旧数据。这些过程在表 DLevelModel 上陷入死锁。这是架构:

滚动条图像
(来源:barramsoft.com

DFile:主键 = DFileID
DLevel:主键 = DLevelID,外键:DFileID
模型:主键 = ModelID,外键:DFileID
ELement:主键= ElementID,外键1:DFileID,外键2:DLevelID

我已经隔离了导致死锁的两个 SQL 语句(每个存储过程各一个)。我已经看到这两个过程报告的死锁。我在这两种情况下都使用 top (1000),并且这两个语句都在循环中执行,直到它们完成且没有任何行可供删除/插入。

SQL 语句 1:

while (...)
begin
    delete top (1000) from DLevel where DFileID = @fileID1
    ...
end

SQL 语句 2:

while (...)
begin
    insert into Element (ElementID, DFileID, LevelNum, ...)
       select top (1000) el.ElementID, el.DFileID, el.LevelNum, ...
       from   ElementLoader el with (nolock)
              left outer join Element e with (nolock)
                   on e.ElementID = el.ElementID
       where  el.DFileID = @fileID2
       and    e.ElementID is null
       order  by el.ElementID
    ...
end

注意:@fileID1@fileID2 的值始终保证有所不同。 DLevel 表平均大约有。单个 DFileID 包含 60 行,因此一次即可完成所有行的删除。

如何避免这两个 SQL 语句之间出现死锁?

编辑1: 重写以更好地澄清问题;添加图像;简化了 SQL 并删除了与 DLevel 表的连接,这不会导致死锁。

编辑2: 添加了死锁图的XML。
Model 表上现在发生死锁。 Model 的删除语句和模式与 DLevel 表类似。

<deadlock victim="process2bae38">
    <process-list>
        <process id="process2bae38" taskpriority="0" logused="4760" waitresource="PAGE: 11:1:1946" waittime="46" ownerId="4127445" transactionname="DELETE" lasttranstarted="2010-06-24T16:19:00.107" XDES="0xffffffff90552ae0" lockMode="S" schedulerid="1" kpid="14252" status="suspended" spid="58" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-24T16:19:00.107" lastbatchcompleted="2010-06-24T16:19:00.107" clientapp=".Net SqlClient Data Provider" hostname="LT0103" hostpid="1668" loginname="NT AUTHORITY\SYSTEM" isolationlevel="read committed (2)" xactid="4127445" currentdb="11" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
            <executionStack>
                <frame procname="CadExplorer5.dbo.pCleanUpOldFiles" line="364" stmtstart="23718" stmtend="23834" sqlhandle="0x03000b00fb1c2229b1a7f7009f9d00000100000000000000">
delete top (@batchSize) from Model where DFileID = @fileID     </frame>
            </executionStack>
            <inputbuf>
Proc [Database Id = 11 Object Id = 690101499]    </inputbuf>
        </process>
        <process id="process2c95b8" taskpriority="0" logused="283388" waitresource="KEY: 11:72057594039304192 (8100bdf15e8b)" waittime="78" ownerId="4127412" transactionname="INSERT" lasttranstarted="2010-06-24T16:19:00.103" XDES="0xffffffff81d5ef18" lockMode="S" schedulerid="2" kpid="8460" status="suspended" spid="63" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-24T16:18:59.413" lastbatchcompleted="2010-06-24T16:18:59.413" clientapp=".Net SqlClient Data Provider" hostname="LT0103" hostpid="1668" loginname="NT AUTHORITY\SYSTEM" isolationlevel="read committed (2)" xactid="4127412" currentdb="11" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
            <executionStack>
                <frame procname="CadExplorer5.dbo.pLoadElements" line="288" stmtstart="28796" stmtend="33194" sqlhandle="0x03000b00a689fe2b2c5107019f9d00000100000000000000">
insert into Element (
                        ElementID, DFileID, ModelID, ElementTypeID, CADElementID,
                        ParentID,
                        LevelNum,
                        Depth, NumChildren,
                        Color, Weight, Style, Xlo, Ylo, Zlo, Xhi, Yhi, Zhi,
                        Diagonal, XCenter,
                        BitFlags, ElementModTime
                        )
                  select top (@batchSize)
                        el.ElementID, el.DFileID, el.ModelID, el.ElementTypeID, el.CADElementID,
                        parent.ElementID as ParentID,
                        (case when el.LoaderType = 1 and et.IsGraphical = 1 then el.LevelAttrib else null end) as LevelNum,
                        --l.LevelNum,
                        el.Depth, el.NumChildren,
                        el.Color, el.Weight, el.Style, el.Xlo, el.Ylo, el.Zlo, el.Xhi, el.Yhi, el.Zhi,
                        el.Diagonal, el.XCenter,     </frame>
            </executionStack>
            <inputbuf>
Proc [Database Id = 11 Object Id = 738101670]    </inputbuf>
        </process>
    </process-list>
    <resource-list>
        <pagelock fileid="1" pageid="1946" dbid="11" objectname="CadExplorer5.dbo.Element" id="lockffffffff86ffd080" mode="IX" associatedObjectId="72057594039107584">
            <owner-list>
                <owner id="process2c95b8" mode="IX"/>
            </owner-list>
            <waiter-list>
                <waiter id="process2bae38" mode="S" requestType="wait"/>
            </waiter-list>
        </pagelock>
        <keylock hobtid="72057594039304192" dbid="11" objectname="CadExplorer5.dbo.Model" indexname="PK_Model" id="lockffffffff8d66db80" mode="X" associatedObjectId="72057594039304192">
            <owner-list>
                <owner id="process2bae38" mode="X"/>
            </owner-list>
            <waiter-list>
                <waiter id="process2c95b8" mode="S" requestType="wait"/>
            </waiter-list>
        </keylock>
    </resource-list>
</deadlock>

I have two stored procedures running in separate threads, running on SQL Server 2005. One procedure inserts new rows into a set of tables and the other procedure deletes old data from the same set of tables. These procedures are running into a deadlock on the tables DLevel and Model. Here is the schema:

Scrollbar Image
(source: barramsoft.com)

Table DFile: Primary Key = DFileID
Table DLevel: Primary Key = DLevelID, Foreign Key: DFileID
Table Model: Primary Key = ModelID, Foreign Key: DFileID
Table ELement: Primary key = ElementID, Foreign Key1: DFileID, Foreign Key2: DLevelID

I have isolated the exact two SQL statements (one from each stored procedure) that are causing the deadlock. I have seen the deadlock reported by either of the procedures. I use top (1000) in both cases and both statements are executed in a loop until they complete with no rows left to delete/insert.

SQL Statement 1:

while (...)
begin
    delete top (1000) from DLevel where DFileID = @fileID1
    ...
end

SQL Statement 2:

while (...)
begin
    insert into Element (ElementID, DFileID, LevelNum, ...)
       select top (1000) el.ElementID, el.DFileID, el.LevelNum, ...
       from   ElementLoader el with (nolock)
              left outer join Element e with (nolock)
                   on e.ElementID = el.ElementID
       where  el.DFileID = @fileID2
       and    e.ElementID is null
       order  by el.ElementID
    ...
end

Note: The values for @fileID1 and @fileID2 are always guaranteed to be different. DLevel table has on average approx. 60 rows for a single DFileID and thus would complete deletion of all rows in a single pass.

How can I avoid a deadlock between these two SQL statements?

Edit 1:
Rewritten to better clarify issue; added image; simplified SQL and removed join to DLevel table, which did not contribute to deadlock.

Edit 2:
Added XML of deadlock graph.
Deadlock now occurs on Model table. Similar delete statement and schema for Model as for DLevel table.

<deadlock victim="process2bae38">
    <process-list>
        <process id="process2bae38" taskpriority="0" logused="4760" waitresource="PAGE: 11:1:1946" waittime="46" ownerId="4127445" transactionname="DELETE" lasttranstarted="2010-06-24T16:19:00.107" XDES="0xffffffff90552ae0" lockMode="S" schedulerid="1" kpid="14252" status="suspended" spid="58" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-24T16:19:00.107" lastbatchcompleted="2010-06-24T16:19:00.107" clientapp=".Net SqlClient Data Provider" hostname="LT0103" hostpid="1668" loginname="NT AUTHORITY\SYSTEM" isolationlevel="read committed (2)" xactid="4127445" currentdb="11" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
            <executionStack>
                <frame procname="CadExplorer5.dbo.pCleanUpOldFiles" line="364" stmtstart="23718" stmtend="23834" sqlhandle="0x03000b00fb1c2229b1a7f7009f9d00000100000000000000">
delete top (@batchSize) from Model where DFileID = @fileID     </frame>
            </executionStack>
            <inputbuf>
Proc [Database Id = 11 Object Id = 690101499]    </inputbuf>
        </process>
        <process id="process2c95b8" taskpriority="0" logused="283388" waitresource="KEY: 11:72057594039304192 (8100bdf15e8b)" waittime="78" ownerId="4127412" transactionname="INSERT" lasttranstarted="2010-06-24T16:19:00.103" XDES="0xffffffff81d5ef18" lockMode="S" schedulerid="2" kpid="8460" status="suspended" spid="63" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-24T16:18:59.413" lastbatchcompleted="2010-06-24T16:18:59.413" clientapp=".Net SqlClient Data Provider" hostname="LT0103" hostpid="1668" loginname="NT AUTHORITY\SYSTEM" isolationlevel="read committed (2)" xactid="4127412" currentdb="11" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
            <executionStack>
                <frame procname="CadExplorer5.dbo.pLoadElements" line="288" stmtstart="28796" stmtend="33194" sqlhandle="0x03000b00a689fe2b2c5107019f9d00000100000000000000">
insert into Element (
                        ElementID, DFileID, ModelID, ElementTypeID, CADElementID,
                        ParentID,
                        LevelNum,
                        Depth, NumChildren,
                        Color, Weight, Style, Xlo, Ylo, Zlo, Xhi, Yhi, Zhi,
                        Diagonal, XCenter,
                        BitFlags, ElementModTime
                        )
                  select top (@batchSize)
                        el.ElementID, el.DFileID, el.ModelID, el.ElementTypeID, el.CADElementID,
                        parent.ElementID as ParentID,
                        (case when el.LoaderType = 1 and et.IsGraphical = 1 then el.LevelAttrib else null end) as LevelNum,
                        --l.LevelNum,
                        el.Depth, el.NumChildren,
                        el.Color, el.Weight, el.Style, el.Xlo, el.Ylo, el.Zlo, el.Xhi, el.Yhi, el.Zhi,
                        el.Diagonal, el.XCenter,     </frame>
            </executionStack>
            <inputbuf>
Proc [Database Id = 11 Object Id = 738101670]    </inputbuf>
        </process>
    </process-list>
    <resource-list>
        <pagelock fileid="1" pageid="1946" dbid="11" objectname="CadExplorer5.dbo.Element" id="lockffffffff86ffd080" mode="IX" associatedObjectId="72057594039107584">
            <owner-list>
                <owner id="process2c95b8" mode="IX"/>
            </owner-list>
            <waiter-list>
                <waiter id="process2bae38" mode="S" requestType="wait"/>
            </waiter-list>
        </pagelock>
        <keylock hobtid="72057594039304192" dbid="11" objectname="CadExplorer5.dbo.Model" indexname="PK_Model" id="lockffffffff8d66db80" mode="X" associatedObjectId="72057594039304192">
            <owner-list>
                <owner id="process2bae38" mode="X"/>
            </owner-list>
            <waiter-list>
                <waiter id="process2c95b8" mode="S" requestType="wait"/>
            </waiter-list>
        </keylock>
    </resource-list>
</deadlock>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请止步禁区 2024-09-13 14:29:22

一种可能的情况:一个连接在 Element 中插入一行,该行引用 DLevel 中的一行,并且 DLevel 中的该行正被另一个连接删除。您的 nolock 提示不适用于外键。

One possible scenario: one connection insert a row in Element, and that row refers to a row in DLevel, and that row in DLevel is being deleted by another connection. Your nolock hint does not apply to foreign keys.

离线来电— 2024-09-13 14:29:22

您可以尝试从 Element 表中删除 DLevel.DFileID 的外键。由于您在 DLevel.DlevelID 上有一个主键,并且您将其引用为 Element 中的外键,因此实际上并不需要 DFileID 外键。

You might try removing the Foreign Key to DLevel.DFileID from the Element table. Since you have a Primary Key on DLevel.DlevelID and you reference that as a Foreign key in Element, the DFileID foreign key is not really needed.

梦明 2024-09-13 14:29:22

我怀疑删除和插入同时进行一定存在某种关键违规......?

I suspect there must be some kind of key violation with delete and insert going at same time..?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文