我有一个C#windows服务,它正在通过一个exec sp_executesql呼叫写入SQL Server 2012数据库.

exec sp_executesql N'Insert into [table name redacted] 
(trial.[field redacted],trial.[field redacted],trial.[Duration],trial.[Count],trial.[Step],trial.[Target],trial.[ResultData],trial.[SessionDateTime],trial.[field redacted],trial.[ModifiedOn],trial.[CreatedOn],trial.[field redacted],trial.[SerialNumber],trial.[Category],trial.[CreatedBy],trial.[ModifiedBy],trial.[Status],trial.[IsEnabled],trial.[IsImmutable],trial.[IsHidden],trial.[Ordinal],trial.[IconUrl],trial.[Url],trial.[DataName],trial.[DisplayName],trial.[Description]) 
values (@field redacted_0,@field redacted_0,@Duration_0,@Count_0,@Step_0,@Target_0,@ResultData_0,@SessionDateTime_0,@field redacted_0,@ModifiedOn_0,@CreatedOn_0,@field redacted_0,@SerialNumber_0,@Category_0,@CreatedBy_0,@ModifiedBy_0,@Status_0,@IsEnabled_0,@IsImmutable_0,@IsHidden_0,@Ordinal_0,@IconUrl_0,@Url_0,@DataName_0,@DisplayName_0,@Description_0)',
N'@field redacted_0 uniqueidentifier,@field redacted_0 nvarchar(4000),@Duration_0 bigint,@Count_0 int,@Step_0 nvarchar(4000),@Target_0 nvarchar(4000),@ResultData_0 nvarchar(4000),@SessionDateTime_0 datetime,@field redacted_0 uniqueidentifier,@ModifiedOn_0 datetime,@CreatedOn_0 datetime,@field redacted_0 uniqueidentifier,@SerialNumber_0 nvarchar(8),@Category_0 nvarchar(4000),@CreatedBy_0 nvarchar(11),@ModifiedBy_0 nvarchar(11),@Status_0 nvarchar(6),@IsEnabled_0 bit,@IsImmutable_0 bit,@IsHidden_0 bit,@Ordinal_0 int,@IconUrl_0 nvarchar(4000),@Url_0 nvarchar(4000),@DataName_0 nvarchar(4000),@DisplayName_0 nvarchar(12),@Description_0 nvarchar(4000)',@field redacted_0='BB52C791-28BC-EC11-BE10-E884A50CE990',@field redacted_0=NULL,@Duration_0=0,@Count_0=0,@Step_0=NULL,@Target_0=N'',
@ResultData_0=NULL,@SessionDateTime_0='2022-04-19 17:57:23',@field redacted_0='F626F234-0AC0-EC11-BE11-E884A50CE990',@ModifiedOn_0='2022-04-19 17:59:15.590',@CreatedOn_0='2022-04-19 17:59:15.590',@field redacted_0='EEFB196C-0AC0-EC11-BE11-E884A50CE990',@SerialNumber_0=N'00000057',@Category_0=NULL,@CreatedBy_0=N'John Stamos',@ModifiedBy_0=N'John Stamos',@Status_0=N'Normal',@IsEnabled_0=1,@IsImmutable_0=0,@IsHidden_0=0,@Ordinal_0=0,@IconUrl_0=NULL,@Url_0=NULL,@DataName_0=NULL,@DisplayName_0=N'Mobile Trial',@Description_0=NULL

通常,插入几乎是瞬时的.有时,可能是1000次中的1次,它会导致错误

Win32异常:等待操作超时

我对SQL Server数据库管理一点也不熟练,我的搜索结果让我找到了许多读取修复程序,包括exec sp_updatestatswith (NOLOCK)个修复程序,但我不知道在处理插入时如何解决这个问题,甚至不知道如何弄清楚我是如何进入这种状态的.我们目前根本没有(有意地)使用事务,所以应该有最小的锁定.我们在表中插入了480万行,它确实有一个外键指向另一个只有116K行的表.

下面是表模式.我正在寻找一些关于如何确定导致此问题的原因的帮助.这只会在生产中发生,当然是间歇性的,所以故障排除一直很困难.

table schema

提前谢谢.

UPDATE:根据@Charlieface的建议,我在遇到超时时运行了查询,得到了这些结果.

Wait Query Results

如何利用这些信息找出导致锁定的原因?我猜等待命令很重要,但这是我目前唯一的猜测.

UPDATE 2:这是SQLException(与Win32Exception相反)

2022-04-20 16:00:47861[4]错误网络.例外MarshallingErrorHandler-系统.数据SqlClient.SqlException(0x80131904):执行超时已过期.操作完成前的超时时间或服务器未响应--->系统组件模型.Win32异常(0x80004005):等待操作超时

推荐答案

从阻塞链脚本的结果可以看出,阻塞链的头的状态为AWAITING COMMAND.这意味着它可能有一个开放的事务,该事务被挂起,同时持有锁.在服务器决定断开连接之前,所有其他事务都会在锁定的行或对象上被阻止.这会导致超时.解决方案是增加命令或锁定超时,因为这不能解决根本原因.

I suggest you take a close look at the code which fires that command.它可以通过两种方式使用事务:

  1. 在同一批或过程中使用服务器端BEGIN TRANCOMMIT语句.

    In the event of a batch-aborting error, the transaction is left hanging until the connection is closed or reset.
    But due to the way ADO.Net manages the connection pool, this does not happen until the connection is reused or a 4-minute timeout expires. (This is irrespective of the use of using on the connection object.)

  2. 使用SqlTransaction.BeginTransaction的客户端事务.

    In the event of an exception, a using statement will normally ensure successful rollback and release of locks.
    But this sometimes does not happen successfully, for example if the client loses network connection.

The solution to both of these is:

  • 在连接、事务、命令和读取器对象上使用using语句.这将在客户端出现异常时尽最大努力回滚.
  • Ensure that XACT_ABORT is set to ON. This means that the server will always rollback in the event of an error.
    You can do this as part of the batch or procedure, or better: set it as the default server-wide.

使用服务器端事务通常比客户端事务好,因为在客户端失go 网络连接的情况下,服务器将不知道如何回滚.

Sql相关问答推荐

如何将varchar传递给tvf并使用该参数来查询结果SQL服务器

获取家谱树中第一次出现的特定信息,然后停止

如何在一个范围内进行分组.""范围值在范围表中定义

在SQL中创建一个计数器,根据BigQuery/SQL中的条件递归地添加行值

当一个视图在Postgres中失效时?

检索上一个星期四和上一个星期三

我可以在SQL的IN子句中使用比子查询包含的值更少的值吗?

动态组/转置

Oracle PL/SQL:解决DBMS输出大小限制的问题

从JSON值数组创建扁平数组Athena

在 Postgres 中将结果按几十年划分

按二维数组的第一个元素排序

对现有记录进行分组

日期逻辑(查找过go 90 天内的第一个匹配行)

将空 JSON 数组添加到 SQL Server 表列中的 JSON 字符串

什么是 100.它与 100 有什么区别?

在presto sql中解析带有区域的时间格式

获取所有用户的第一次和最后一次发货以及到达日期

在 postgresql 中,我可以将其组合成一个查询吗?

Select 给定类别列表(或更多类别)中的所有事物