这令人困惑。工作正常的我的ASP.NET 3.5应用程序突然开始出现超时错误...
System.Data.SqlClient.SqlException:超时已过期。操作完成之前经过的超时时间或服务器没有响应
...但仅适用于连接字符串中具有正确用户名/密码的请求。如果我们故意弄乱配置中的连接字符串,SQL Server会正确拒绝请求,但是不会在15秒等待(配置超时)之后立即拒绝,清楚地表明它与服务器通信没有问题。
我们退回了SQL Server框(SQL Server 2005,完全修补)和IIS框,触摸了web.config以强制重启应用程序等,但没有运气。所有请求都会挂起15秒,然后报告该错误。在任何时候我们都能够直接访问数据库服务器(管理工作室,监控工具),并且我能够在Visual Studio中配置我的本地站点副本,以便在没有事故的情况下命中同一个数据库服务器。这个突然出现的问题持续了大半天(错误开始在早上6:17登录)突然在下午4:30左右解决了。
似乎在这个Web服务器和这个数据库服务器之间存在网络路由问题,但只有一组特定的SQL凭据。我知道这没有任何意义,但我们可以想象没有任何其他情况。我是一位非常有经验的开发人员,无论是我和我们经验丰富的DBA还是系统管理员都无法在事件日志,监控违规行为等方面找到任何可以为这种奇异且自我解决的症状提供合理解释的方法。
这发生在我们客户的测试环境中,这并不理想,但是因为我们不明白到底发生了什么,我们担心的是这可能会突然出现在生产中,我们会在墙上击败我们的集体头脑所以任何想法或狂野的理论都非常受欢迎。
正在爆炸的LINQ-to-SQL生成的代码行是ExecuteMethodCall:
[Function(Name="dbo.spSetModelingNodeState")]
public int spSetModelingNodeState([Parameter(Name="NodeIdentifier", DbType="VarChar(60)")] string nodeIdentifier, [Parameter(Name="NodeStatus", DbType="Int")] System.Nullable<int> nodeStatus, [Parameter(Name="PoolWeighting", DbType="Float")] System.Nullable<double> poolWeighting)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), nodeIdentifier, nodeStatus, poolWeighting);
return ((int)(result.ReturnValue));
}
我调用该代码的代码是(缩写):
using (MyDataContext myDataContext = new MyDataContext(_connectionString))
{
myDataContext.spSetModelingNodeState(
Adapter.Identifier, // string
(int)newHealthValue, // enum, cast to int
PoolWeighting); // float
}
编辑:花了几天时间追踪,但我在下面添加了日志/个人资料信息,每个评论员请求以及有问题的存储过程正文
SQL Server日志只显示登录和注销,没有任何问题迹象。 Profiler曲线也没有吸烟枪,但以下似乎显示声明需要18秒。关注spid 82.它从4:37:50开始,做了一些事情,然后在4:38:07点了83条记录登录。 Spid 82接下来会以4:38:07的开始时间记录它的完成情况,但由于它们是按顺序记录的,所以它必须实际发生在4:38:07(之前的跟踪语句)和4:40:10之间(以下)语句)。
Spid Starttime Event Query 82 4:37:50 PM Login -- network protocol: LPC set quoted_identifier on set arithabort off set numeric_roundabort off set ansi_warnings on set ansi_padding on set ansi_nulls on set concat_null_yields_null on set cursor_close_on_commit off set implicit_transactions off 82 4:37:50 PM SP:StmtStarting EXEC @RETURN_VALUE = [dbo].[spSetModelingNodeState] @NodeIdentifier = @p0, @NodeStatus = @p1, @PoolWeighting = @p2 82 4:37:50 PM SP:Starting EXEC @RETURN_VALUE = [dbo].[spSetModelingNodeState] @NodeIdentifier = @p0, @NodeStatus = @p1, @PoolWeighting = @p2 82 4:37:50 PM SP:StmtStarting UPDATE ModelingNodeState SET NodeStatus = @NodeStatus, PoolWeighting = ISNULL(@PoolWeighting, PoolWeighting) WHERE NodeIdentifier = @NodeIdentifier 83 4:38:07 PM Login -- network protocol: LPC set quoted_identifier on set arithabort off set numeric_roundabort off set ansi_warnings on set ansi_padding on set ansi_nulls on set concat_null_yields_null on set cursor_close_on_commit off set implicit_transactions off 82 4:37:50 PM SP:Completed EXEC @RETURN_VALUE = [dbo].[spSetModelingNodeState] @NodeIdentifier = @p0, @NodeStatus = @p1, @PoolWeighting = @p2 80 4:40:10 PM SP:StmtStarting SELECT 'Server[@Name=' + quotename(CAST(serverproperty(N'Servername') AS sysname),'''') + ']' + '/Database[@Name=' + quotename(db_name(),'''') + ']' + '/Table[@Name=' + quotename(tbl.name,'''') + ' and @Schema=' + quotename(SCHEMA_NAME(tbl.schema_id),'''') + ']' AS [Urn], tbl.name AS [Name], SCHEMA_NAME(tbl.schema_id) AS [Schema], CAST( case when tbl.is_ms_shipped = 1 then 1 when ( select major_id from sys.extended_properties where major_id = tbl.object_id and minor_id = 0 and class = 1 and name = N'microsoft_database_tools_support') is not null then 1 else 0 end AS bit) AS [IsSystemObject], tbl.create_date AS [CreateDate], stbl.name AS [Owner] FROM sys.tables AS tbl INNER JOIN sys.database_principals AS stbl ON stbl.principal_id = ISNULL(tbl.principal_id, (OBJECTPROPERTY(tbl.object_id, 'OwnerId'))) WHERE (CAST( case when tbl.is_ms_shipped = 1 then 1 when ( select major_id from sys.extended_properties where major_id = tbl.object_id and minor_id = 0 and class = 1 and name = N'microsoft_database_tools_support') is not null then 1 else 0 end AS bit)=@_msparam_0) ORDER BY [Schema] ASC,[Name] ASC 80 4:40:10 PM SQL:BatchStarting use [master] 62 4:20:10 PM Logout NULL 55 4:20:02 PM Logout NULL 74 4:13:37 PM Logout NULL 59 4:20:10 PM Logout NULL 55 4:40:29 PM Login -- network protocol: TCP/IP set quoted_identifier on set arithabort off set numeric_roundabort off set ansi_warnings on set ansi_padding on set ansi_nulls on set concat_null_yields_null on set cursor_close_on_commit off set implicit_transactions 55 4:40:29 PM SQL:BatchStarting set transaction isolation level read committed set implicit_transactions off 82 4:37:50 PM Logout NULL
这绝对是一个比我习惯的更深层次的SQL调试,所以如果我误读了这一点,请告诉我,但看起来这个声明似乎没有发生任何事故,只是非常缓慢。再次,它事先运行正常,开始超时,然后恢复正常运行。
我现在唯一能想到的就是我在公共场合反复思考的是,如果有一些长时间运行的锁堵塞了sproc调用的表,那可能就解释了它。因为LINQ-to-SQL在某种程度上隐藏了登录/注销过程,所以登录可能总是正常工作,而这只是一个由于块而超时的sproc调用。这些表是否被锁定,如果是,为什么,在这一点上是不可能的。这听起来像是我看到的最可能的解释,还是有人有另一种理论?
为了完整性,这里是sproc的主体:
/****** Object: StoredProcedure [dbo].[spSetModelingNodeState] Script Date: 10/29/2010 14:37:46 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spSetModelingNodeState]
(
@NodeIdentifier varchar(60),
@NodeStatus int,
@PoolWeighting float = NULL
)
AS
/*try to update existing row to new state*/
UPDATE
ModelingNodeState
SET
NodeStatus = @NodeStatus,
PoolWeighting = ISNULL(@PoolWeighting, PoolWeighting)
WHERE
NodeIdentifier = @NodeIdentifier
IF @@ROWCOUNT = 0
/*not found, so insert new one*/
INSERT
ModelingNodeState(
NodeIdentifier,
PoolWeighting,
NodeStatus,
LastModelingResult)
VALUES(
@NodeIdentifier,
ISNULL(@PoolWeighting, 1),
0,
NULL)
DECLARE @timestamp datetime
SET @timestamp = CURRENT_TIMESTAMP
/*fill endtime of previous node state*/
UPDATE
ModelingNodeStateLog
SET
EndTime = @timestamp
WHERE
EndTime IS NULL AND
NodeIdentifier = @NodeIdentifier AND
NodeStatus <> @NodeStatus
/*start a new entry in the log (yes, I saw I should remove the IF check and always insert, but that's how it currently is in the db)*/
IF @@ROWCOUNT <> 0
INSERT
ModelingNodeStateLog
(
NodeIdentifier,
NodeStatus,
StartTime
)
VALUES
(
@NodeIdentifier,
@NodeStatus,
@timestamp
)
RETURN
答案 0 :(得分:1)
由于其他人没有插话,我将假设我所发生的进化理论是正确的。具体来说,这是由于在ModelingNodeState或ModelingNodeStateLog表上锁定了尚未确认的原点,导致语句超时,而不是连接超时。 LINQ-to-SQL通常便于管理连接,这种区别被混淆了。
这与所有观察到的症状一致:
经验教训:
感谢社群的反馈,引导我(让我们希望)正确答案!
答案 1 :(得分:0)
从其他计算机还原数据库备份后,我看到了这种行为。
这可以通过管理工作室中的SQL命令修复。见How to fix orphaned SQL Server users