我记录了ASP.NET-Application抛出的异常.
消息:事务(进程ID 56)在锁定时死锁 与另一个进程通信缓冲资源并被选为死锁牺牲品.重新运行该交易.
我确定它的原因是,我selects在SSMS中直接运行了一些在同一时间在应用程序中查询的表.
所以现在我的问题是:
先感谢您.
这是表格(简化):
Table "public.link"
Column | Type | Modifiers
---------------+-----------------------------+---------------------------------------------------
id | integer | not null default nextval('link_id_seq'::regclass)
page_id | integer |
placed_at | timestamp without time zone | default now()
Indexes:
"link_pkey" PRIMARY KEY, btree (id)
"link_page_id_index" btree (page_id)
Foreign-key constraints:
"link_page_id_foreign_key" FOREIGN KEY (page_id) REFERENCES page(id) ON UPDATE RESTRICT ON DELETE RESTRICT
这里是查询(简化):
UPDATE link SET page_id = ?, placed_at = now()
WHERE id IN ( SELECT id FROM link ... ) AND page_id IS NOT NULL
死锁消息:
ERROR: …
我的申请中间歇性地陷入僵局.我的应用程序有1个表,例如EMPLOYEE(ID(PK),NAME,SAL),有2个会话.
第一节:
SELECT ID, NAME, SAL FROM EMPLOYEE WHERE SAL = (SELECT MIN(SAL) FROM
EMPLOYEE) FOR UPDATE
Let say the query return EMPLOYEE ROW having ID=2
then application does some processing like rs.updateInt(ID_SAL, 10);
Run Code Online (Sandbox Code Playgroud)
第2节:(针对其他业务逻辑)
SELECT ID, NAME, SAL FROM EMPLOYEE WHERE ID=2 FOR UPDATE.
Run Code Online (Sandbox Code Playgroud)
因此,在应用程序中,两个会话都尝试更新同一行(在ID = 2的示例行中)这种情况是预期的,因此我认为SELECT .. FOR UPDATE将有所帮助.
难道我做错了什么?我假设SELECT FOR UPDATE将锁定该行,当其他会话将尝试更新同一行时,它将等待会话1完成执行.
在测试多个用户的应用程序时,我遇到了ORA-00060死锁错误.我不知道如何确定这个错误的原因,所以如果有人能帮助我,我将不胜感激.
我查看了为此事件生成的跟踪文件,它显示了导致此问题的查询:
UPDATE TABLE_A SET CK=CK+1 WHERE A_ID=(
SELECT A_ID FROM TABLE_B WHERE SOME_COLUMN=:SOMECOLUMN
)
Run Code Online (Sandbox Code Playgroud)
它还产生了这个:
[Transaction Deadlock]
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TM-0002a675-00000000 51 200 SX SSX 52 22 SX SSX
TM-0002a675-00000000 52 …Run Code Online (Sandbox Code Playgroud) stackoverflow 上已经有这个问题的不同版本,但没有一个版本可以帮助我深入了解问题。因此,我在这里再次详细介绍我的问题。
我们一直随机得到Transaction (Process ID xx) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.. 让我澄清一下,这不是行级或表级锁定。我已经尝试了足够多的猜测/随机的事情;我需要有关如何解决通信缓冲区死锁问题的准确分步指南。
如果您对具体细节感兴趣,请继续阅读。
场景的具体细节:我们有一个非常简单的基于 Dapper ORM 的 C# .net core Web API,它接受请求并对托管在该 Microsoft Sql 服务器上的数据库执行 CRUD 操作。为此,连接管理器(注册为范围服务)IDbConnection在请求范围内打开一个新连接;该连接用于执行删除、插入、更新或获取。对于插入/更新/删除 C# 行看起来像这样await connection.ExecuteAsync("<Create update or delete statement>", entity);对于GET请求,我们只需运行await connection.QueryFirstOrDefaultAsync<TEntity>("<select statement>", entity);; 有 5 种类型的实体(全部呈现简单的非关系表)。它们都是通过 ID 进行 CRUD 的。
到目前为止已经尝试过什么
我在我的实时应用程序中遇到了死锁错误,并将它们(使用sql server profiler的"死锁图")跟踪到after insert我的表上定义的触发器.
基本上情况是这样的 - 我想跟踪插入到某些表中的记录,按时间范围分组.(即在12:00-12:10之间,插入了7条记录Users).
我实现它的方法是after insert在这些表上创建触发器,因此当插入记录时,我将更新统计表中的相应记录.(见下文).
正如我所说,这似乎造成了僵局.发生的事情(我认为,我还没有找到确定的方法)是每个事务可以在提交之前在几个表中插入/更新几个记录.
因此事务1出现,更新统计表中的某个记录(从而锁定它),然后继续更新表B中的记录.
同时,事务2将记录插入表B(从而锁定它),并尝试更新统计信息表中的记录 - 导致死锁.
(这当然是可能发生的事情的简化版本.实际上我还不是100%肯定).
现在我最初的想法是看看是否可以在提交后执行触发器,以便事务不再持有任何锁.
但是,据我所知,没有这样的选择.
另一个解决方案是完全消除触发器,并使用某种批处理作业.
关于首选解决方案的任何其他想法/想法都会受欢迎.
触发代码:
SELECT @TimeIn = I.TimeIn,
@TimeOut = I.[TimeOut],
FROM Inserted AS I
SET @NoOfPAX = 1
SET @Day = DATEADD(dd,0,DATEDIFF(dd,0,@TimeOut))
SET @HourOfTheDay = DATEPART (HOUR, @TimeOut)
SET @MinuteOfTheHour = DATEPART (MINUTE, @TimeOut)
SELECT @HourlyStatsExists = COUNT(*)
FROM dbo.DataWarehouse_HourlyStats
WHERE [Day] = @Day
AND HourOfTheDay = @HourOfTheDay
AND MinuteOfTheHour = @MinuteOfTheHour
IF …Run Code Online (Sandbox Code Playgroud) 我们的Java应用程序通过cron作业清除日志表中的数据.以下是为清理而执行的查询:
DELETE FROM AU_TRANSACTIONDATA
WHERE AU_ACTIVITYENDTIME != 0
AND AU_ACTIVITYENDTIME <= 1464570001151
Run Code Online (Sandbox Code Playgroud)
我们在AU_ACTIVITYENDTIME这个表的列上有一个索引:
CREATE INDEX [IX_AU_TRANSDATA_ENDTIME]
ON [AU_TRANSACTIONDATA]([AU_ACTIVITYENDTIME]) ON [PRIMARY];
Run Code Online (Sandbox Code Playgroud)
我们的应用程序将事务数据(在我们的应用程序中执行API时生成)转储到此表中.这是INSERT查询:
INSERT INTO AU_TRANSACTIONDATA (AU_TRANSACTIONID, AU_TRANSACTIONNAME, AU_TRANSACTIONDOMAINID, AU_ACTIVITYNAME, AU_ACTIVITYID, AU_ACTIVITYPID, AU_ACTIVITYTYPE, AU_ACTIVITYSTARTTIME, AU_ACTIVITYENDTIME, AU_ACTIVITYSTATUS, AU_CORRECTDATA, AU_ERRORDATA, AU_USERID, AU_GROUPID, AU_NODENAME, AU_TRANSACTIONDESCRIPTION, AU_SEQUENCEID, AU_TRANSSEQUENCEID)
VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8, @P9, @P10, @P11, @P12, @P13, @P14, @P15, @P16, @P17)
Run Code Online (Sandbox Code Playgroud)
当日志清理(DELETE查询)和数据处理(INSERT查询)同时发生时,我们面临问题.我们有大约150万条记录用于清理,因此删除查询需要一些时间来清理日志记录.但在此期间,处理被阻止,没有INSERT查询通过.
这是日志:
SPID at Head of Blocking Chain:
SPID [ecid]: 3524 …Run Code Online (Sandbox Code Playgroud) 遇到SQL Server数据库死锁,可以在SQL日志中看到死锁条目。如何使用日志条目来查找死锁的原因?
我正在游标内运行一个过程。经过多次成功的迭代,我得到了这个:
Transaction (Process ID 104) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
我不会发布完整的详细信息,因此我不期望得到细粒度的调试答案。事实:
select(我看到来自 dm exec 请求的正在运行的查询)如果我的两点没记错的话,是否有可能陷入僵局?死锁是否会要求资源的所有相关用户都对其进行写入操作,这会在资源请求图中创建一个循环?我理解 a 中的超时错误select,但无法理解死锁。我缺少什么?
更新:
我放弃了进一步的调试,因为我注意到我认为存在的索引并不存在。创建时,性能还可以。
然而,为了保持这个有用并希望能找到答案,以下是我调查的更多内容、一些事实和对评论的想法:
首先,sql server版本是2008。我知道这是不支持的。我无法提出建议,更不用说更新服务器了。
我发现 Jeroen Mostert 的评论很有趣。“过去”有多少?我注意到在 sys.dm_os_waiting_tasks 中,会话被自身阻塞多次,且等待类型为 CXPACKET。我做了一些搜索,但选项(maxdop 1)没有解决问题。但是,请记住不存在的索引将导致性能糟糕。难道是附加了正确的并行性,但是操作太多了?尽管如此,我也目睹了巨大的 dm_exec_requests.wait_time。因此,即使查询很糟糕,我还是相信周围存在奇怪的(死)锁。
如果答案/评论提出了跟踪问题的特定查询/步骤,我将很乐意重新创建它。
是否有任何良好的开源或其他免费的MS SQL Server事务阻塞监视工具?能够检测到持续时间超过X的阻塞事务然后通过电子邮件发送警报的人将是理想的选择.
一台服务器很简单.对于MS SQL Express 2008,但应该适用于所有真实或最近的所有.
sql-server ×7
deadlock ×3
sql ×2
t-sql ×2
alert ×1
c# ×1
database ×1
locks ×1
oracle ×1
postgresql ×1
sql-update ×1
sqlexception ×1
ssms ×1
triggers ×1