【发布时间】:2017-12-27 12:48:51
【问题描述】:
下面的存储过程出现死锁错误 - UpdateTestEvents。
下面是xml死锁报告:
<deadlock>
<victim-list>
<victimProcess id="process1128b529468" />
</victim-list>
<process-list>
<process id="process1128b529468" taskpriority="0" logused="0" waitresource="KEY: 7:72057594042777600 (fec90e3a2350)" waittime="2364" ownerId="158290173" transactionname="user_transaction" lasttranstarted="2017-12-17T01:20:45.553" XDES="0x1064ff98408" lockMode="U" schedulerid="9" kpid="6664" status="suspended" spid="57" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-12-17T01:20:45.547" lastbatchcompleted="2017-12-17T01:20:45.543" lastattention="1900-01-01T00:00:00.543" clientapp="EntityFramework" hostname="STAAP8895" hostpid="3616" loginname="XLAPSDBScoring" isolationlevel="read committed (2)" xactid="158290173" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="analytics.dbo.UpdateTestEvents" line="25" stmtstart="1836" stmtend="2132" sqlhandle="0x030007005e4b4b2a97304c0155a5000001000000000000000000000000000000000000000000000000000000">
UPDATE dbo.History
SET Ignore = 0
WHERE Number = @Number
AND dbo.StringsMatch(@candidate, ACType, DEFAULT) = </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 709577566] </inputbuf>
</process>
<process id="process1127e522ca8" taskpriority="0" logused="301092" waitresource="KEY: 7:72057594043039744 (c41e1b4226b6)" waittime="2364" ownerId="158290165" transactionname="user_transaction" lasttranstarted="2017-12-17T01:20:45.447" XDES="0xf8dc5ff8a8" lockMode="U" schedulerid="2" kpid="4888" status="suspended" spid="60" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-12-17T01:20:45.440" lastbatchcompleted="2017-12-17T01:20:45.437" lastattention="1900-01-01T00:00:00.437" clientapp="EntityFramework" hostname="STAAP1493" hostpid="3304" loginname="XLAPSDBScoring" isolationlevel="read committed (2)" xactid="158290165" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="analytics.dbo.UpdateTestEvents" line="32" stmtstart="2370" stmtend="3926" sqlhandle="0x030007005e4b4b2a97304c0155a5000001000000000000000000000000000000000000000000000000000000">
WITH ValidOriginsAndDestinations AS
(
SELECT Origin FROM dbo.History
WHERE Ignore = 0
AND Number = @Number
UNION ALL
SELECT Destination FROM dbo.History
WHERE Ignore = 0
AND Number = @Number
)
UPDATE fh
SET Ignore = 0
FROM dbo.History AS fh
WHERE Number = @Number
AND Ignore = 1
AND
(
Origin IN (SELECT * FROM ValidOriginsAndDestinations)
OR Destination IN (SELECT * FROM ValidOriginsAndDestinations) </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 709577566] </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594042777600" dbid="7" objectname="analytics.dbo.History" indexname="PK_History" id="lockf50c41ac80" mode="X" associatedObjectId="72057594042777600">
<owner-list>
<owner id="process1127e522ca8" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process1128b529468" mode="U" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594043039744" dbid="7" objectname="xl_analytics_aviation.dbo.History" indexname="IX_History_Number" id="lock1128b5be680" mode="U" associatedObjectId="72057594043039744">
<owner-list>
<owner id="process1128b529468" mode="U" />
</owner-list>
<waiter-list>
<waiter id="process1127e522ca8" mode="U" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
存储过程如下所示:
CREATE PROCEDURE [dbo].[UpdateTestEvents]
@Number varchar(50)
AS
DECLARE @tolerance decimal(10,10) = 0.15
DECLARE @totalEvents decimal(10,0) = (SELECT COUNT(*) FROM dbo.History fh WHERE fh.Number = @Number)
IF(@totalEvents = 0) RETURN
DECLARE @candidate VARCHAR(50) =
(SELECT TOP 1 ACType
FROM dbo.History AS fh
WHERE fh.Number = @Number
GROUP BY ACType
HAVING (COUNT(*) / @totalEvents) > @tolerance
ORDER BY MAX(ActualDepartureTime) DESC)
SELECT @candidate
UPDATE dbo.History
SET Ignore = 0
WHERE Number = @Number
AND dbo.StringsMatch(@candidate, ACType, DEFAULT) = 1;
WITH ValidOriginsAndDestinations AS
(
SELECT Origin FROM dbo.History
WHERE Ignore = 0
AND Number = @Number
UNION ALL
SELECT Destination FROM dbo.History
WHERE Ignore = 0
AND Number = @Number
)
UPDATE fh
SET Ignore = 0
FROM dbo.History AS fh
WHERE Number = @Number
AND Ignore = 1
AND
(
Origin IN (SELECT * FROM ValidOriginsAndDestinations)
OR Destination IN (SELECT * FROM ValidOriginsAndDestinations)
);
WITH Comfirmeddt AS
(
SELECT a.lat, a.long FROM dbo.places AS a
JOIN dbo.History AS fh
ON a.tidentifier = fh.Origin
OR a.tidentifier = fh.Destination
WHERE fh.Number = @Number
GROUP BY a.tidentifier, a.lat, a.long
)
UPDATE fh
SET Ignore = 0
FROM dbo.History AS fh
JOIN dbo.places AS a
ON a.tidentifier = fh.Origin
OR a.tidentifier = fh.Destination
WHERE fh.Ignore = 1
AND fh.Number = @Number
AND EXISTS
(
SELECT * FROM Comfirmeddt AS confirmed
WHERE
(
a.lat < confirmed.lat + 0.5 AND a.lat > confirmed.lat - 0.5 AND
a.long < confirmed.long + 0.5 AND a.long > confirmed.long - 0.5
)
)
GO
我收到以下错误: 执行命令时发生错误。有关详细信息,请参阅内部异常。事务(进程 ID 57)与另一个进程在锁资源上死锁,并已被选为死锁牺牲品。重新运行事务
[PK_History]的索引定义如下:
ALTER TABLE [dbo].[History] ADD CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
[HashCode] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
主键是HashCode 有人可以建议我在这个查询上可以做些什么来避免将来出现这种死锁。
请在下面找到表结构:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[History](
[HashCode] [varchar](50) NOT NULL,
[FaID] [varchar](50) NOT NULL,
[Number] [varchar](255) NOT NULL,
[ActualArrivalTime] [datetime] NULL,
[ActualDepartureTime] [datetime] NULL,
[ACType] [varchar](10) NULL,
[Destination] [varchar](40) NULL,
[DestinationCity] [varchar](100) NULL,
[Origin] [varchar](40) NULL,
[Ignore] [bit] NOT NULL DEFAULT ((1)),
[FlNumber] [varchar](255) NULL,
[DateAdded] [datetime] NOT NULL DEFAULT (getdate()),
CONSTRAINT [History] PRIMARY KEY CLUSTERED
(
[HashCode] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
ALTER TABLE [dbo].[History] WITH CHECK ADD CONSTRAINT [FK_Number] FOREIGN KEY([Number])
REFERENCES [dbo].[Number] ([Number])
GO
ALTER TABLE [dbo].[History] CHECK CONSTRAINT [FK_Number]
GO
对存储过程的调用发生在 .NET 代码中,由实体框架实现。下面是从应用程序调用这个存储过程的框架
using (var db = new NumberDbContext())
{
foreach (var tn in Numbers)
{
db.UpdateTestEvents(tailNumber);
}
}
请在下面找到查询的执行计划: https://www.brentozar.com/pastetheplan/?id=B1dGzUMQf
如果 IX_History_Number 索引也定义:
CREATE NONCLUSTERED INDEX [IX_History_Number] ON [dbo].[History]
(
[Number] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
【问题讨论】:
-
PK_Histor 中的主键字段是什么,IX_History_Number 定义是什么?
-
IX_History_Number 是为名为 Number 的列之一创建的非聚集非唯一索引。并且 PK_History 是表的聚集主键索引
-
>>>而 PK_History 是表的聚集主键索引
-
@user2081126,不同的索引访问路径导致了死锁。避免这些死锁的一种快速而简单的方法是在@number 值上使用独占事务级别
sp_getapplock来序列化访问。我假设 proc 是从应用代码中发起的事务调用的。 -
@sepupic:我将用索引的定义更新问题。主键是 HashCode,索引如下所示: ALTER TABLE [dbo].[History] ADD CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED ( [HashCode] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF,ONLINE = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO
标签: sql sql-server stored-procedures deadlock