首页 > 解决方案 > 如何解决锁上死锁的 SqlException 通信缓冲资源

问题描述

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 核心 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。

到目前为止已经尝试过什么

  1. MAXDOP=1 对 SQL 语句的查询提示
  2. 确保一种实体在给定时间点只有 1 个实体 CRUD。
  3. 重新启动 SQL 服务器/应用程序实例
  4. 确保端口/RAM/CPU/网络带宽没有耗尽
  5. 更改 DATABASE XXXXXX SET READ_COMMITTED_SNAPSHOT ON/OFF
  6. 保持交易尽可能小
  7. 持久重试策略作为一种解决方法(处理问题的随机瞬态性质)
  8. 每个实体类型一个线程

服务器规格: 我们在具有 64 个内核和 400GB RAM 的虚拟机中托管了 Microsoft Sql Server 2016 On Azure。此服务器上的通常工作负载是 10% CPU 和 30% RAM,偶尔会上升到 80% CPU 和 350GB RAM。在此问题发生的所有时间,CPU 使用率都低于 20%(大多数情况下在 10% 左右,只有一次是 20%,RAM 在所有情况下都低于 30%)。

根据@Dan Guzman 的请求,死锁 XML 事件

这篇文章的文件太大,所以创建了这个谷歌驱动器文件。请点击以下链接,然后在右上角点击下载。它是一个 zip 文件。

https://drive.google.com/file/d/1oZ4dT8Yrd2uW2oBqBy9XK_laq7ftGzFJ/view?usp=sharing

标签: c#sql-serverdeadlocksqlexceptiondatabase-deadlocks

解决方案


死锁通常是需要查询和索引调整的症状。下面是来自死锁跟踪的示例查询,它表明了死锁的根本原因:

<inputbuf>
@SomeStatus1 nvarchar(4000),@ProductName nvarchar(4000),@ProductNameSide nvarchar(4000),@BayNo nvarchar(4000),@CreatedDateTime datetime,@EffectiveDate datetime,@ForSaleFrom datetime,@ForSaleTo datetime,@SetupInfoNode nvarchar(4000),@LocationNumber nvarchar(4000),@AverageProductPrice decimal(3,2),@NetAverageCost decimal(3,1),@FocustProductType nvarchar(4000),@IsProduceCode nvarchar(4000),@ActivationIndicator nvarchar(4000),@ResourceType nvarchar(4000),@ProductIdentifierNumber nvarchar(4000),@SellingStatus nvarchar(4000),@SectionId nvarchar(4000),@SectionName nvarchar(4000),@SellPriceGroup nvarchar(4000),@ShelfCapacity decimal(1,0),@SellingPriceTaxExclu decimal(2,0),@SellingPriceTaxInclu decimal(2,0),@UnitToSell nvarchar(4000),@VendorNumber nvarchar(4000),@PastDate datetime,@PastPrice decimal(29,0))
UPDATE dbo.ProductPricingTable 
SET SellingPriceTaxExclu = @SellingPriceTaxExclu, SellingPriceTaxInclu = @SellingPriceTaxInclu, 
SellPriceGroup = @SellPriceGroup, 
ActivationIndicator = @ActivationIndicator, 
IsProduceCode = @IsProduceCode, 
EffectiveDate = @EffectiveDate, 
NetCos
</inputbuf>

尽管 SQL 语句文本被截断,但它确实表明所有参数声明都是nvarchar(4000)(ORM 的常见问题)。当 join/where 子句中引用的列类型不同时,这可能会阻止索引的有效使用,从而导致在并发查询期间导致死锁的全扫描。

更改参数类型以匹配引用列的类型,并检查执行计划的效率。


推荐阅读