三种SQL Server超时异常场景的诊断排查及配置疑问
诊断SQL Server超时异常的思路与解决方案
问题背景
近期在不同操作场景下频繁遇到SQL Server超时错误,涉及事务启动、非查询执行、Dapper异步查询三类操作,甚至测试环境无负载时也会触发。当前环境为.NET 6、MARS=false、Windows系统,连接超时设为30秒,CommandTimeout使用默认值。调整连接超时仅解决部分场景问题,禁用MARS、升级至.NET 6均未彻底解决,同时存在两个核心疑问:全局设置CommandTimeout是否对BeginTransaction超时有效?CommandTimeout是否是最后的解决手段?
三种超时异常栈
第一种:事务启动超时
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (258): Unknown error 258 at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error) at System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync() at System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket() at System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer() at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest) at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest) at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName, Boolean shouldReconnect) at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso, String transactionName) at System.Data.SqlClient.SqlConnection.BeginDbTransaction(IsolationLevel isolationLevel) at System.Data.Common.DbConnection.BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
第二种:非查询操作超时
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (258): Unknown error 258 at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult) at System.Data.SqlClient.SqlCommand.EndExecuteNonQuery(IAsyncResult asyncResult) at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
第三种:Dapper异步查询超时
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (258): Unknown error 258 at System.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__126_0(Task`1 result) at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location where exception was thrown --- at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) --- End of stack trace from previous location where exception was thrown --- at Dapper.SqlMapper.QueryAsync[T](IDbConnection cnn, Type effectiveType, CommandDefinition command) in C:\projects\dapper\Dapper\SqlMapper.Async.cs:line 419
诊断与解决方案
一、诊断入手方向
SQL Server端排查
- 查看SQL Server错误日志:检查是否存在死锁、资源耗尽、连接池溢出、服务中断等记录。
- 分析等待统计信息:执行
SELECT * FROM sys.dm_os_wait_stats ORDER BY wait_time_ms DESC,重点关注LCK_M_*(死锁等待)、PAGEIOLATCH_*(IO等待)、RESOURCE_SEMAPHORE(内存等待)等高占比等待类型。 - 监控事务与锁:用
SELECT * FROM sys.dm_tran_locks查看当前锁持有情况,确认是否有长事务阻塞新事务或查询执行。 - 检查连接池状态:通过
SELECT * FROM sys.dm_exec_connections查看活跃连接数,判断是否达到连接池上限(默认100)。
客户端与网络排查
- 捕获网络数据包:使用Wireshark抓取客户端与SQL Server之间的数据包,排查是否存在丢包、延迟过高问题。
- 核对连接字符串配置:明确
Connection Timeout(仅控制连接建立时间)与Command Timeout(控制命令执行时间)的区别,避免混淆配置。 - 监控线程池状态:通过
ThreadPool.GetAvailableThreads()检查.NET线程池是否耗尽,异步任务排队也会表现为超时。
代码层面排查
- 检查事务生命周期:是否存在未及时提交/回滚的长事务,导致后续操作阻塞。
- 验证Dapper命令配置:确认
CommandDefinition是否显式设置超时,未设置则继承连接的默认CommandTimeout。 - 排查异步操作异常:检查是否存在未正确处理的异步任务,导致资源泄漏或连接占用。
二、为何相同超时出现在不同操作中
所有异常的核心根因都是客户端与SQL Server之间的通信或命令执行未在超时时间内完成,不同操作只是触发场景不同:
- 事务启动超时:多因数据库存在阻塞,新事务无法获取必要锁;或连接池中的连接状态异常,重建连接时超时。
- 非查询/查询超时:可能是SQL语句效率低下(无索引、逻辑复杂)、数据库资源不足(CPU/内存/IO过载),或网络延迟导致结果返回缓慢。
- Win32错误258对应
WAIT_TIMEOUT,本质是底层等待操作超时,说明无论连接、事务还是命令,最终都卡在了某个等待环节。
三、关于CommandTimeout的疑问
CommandTimeout对BeginTransaction是否生效?
不生效。BeginTransaction属于连接级操作,受Connection Timeout控制;CommandTimeout仅作用于SQL命令(查询、插入、更新等)的执行阶段。CommandTimeout是否是最后手段?
是的。调整CommandTimeout只是缓解症状,而非解决根因。只有在确认SQL语句已优化、数据库资源充足、网络无问题,但仍存在偶发超时的情况下,才考虑适当延长CommandTimeout,优先应从根因入手解决问题。
四、针对性解决建议
事务启动超时
- 终止阻塞进程:通过
KILL <session_id>终止长事务或阻塞进程,同时优化业务逻辑减少长事务时长。 - 调整连接池配置:适当增加
Max Pool Size,测试环境可临时设置Pooling=false排查连接池问题(生产环境不推荐)。 - 延长连接超时:若数据库服务器负载较高,可将
Connection Timeout从30秒调整至60秒。
- 终止阻塞进程:通过
命令执行超时
- 优化SQL语句:添加合适索引、避免全表扫描、拆分复杂查询。
- 升级数据库资源:检查CPU、内存、磁盘IO使用率,资源不足时升级硬件或调整数据库配置。
- 显式设置CommandTimeout:在Dapper的
CommandDefinition或SqlCommand中设置合理超时(如60秒),避免依赖默认值。
测试环境无负载仍超时
- 重启SQL Server服务:排查服务是否存在隐性异常。
- 验证网络连通性:关闭防火墙测试,或更换网络环境排除网络问题。
- 替换SQL客户端库:使用
Microsoft.Data.SqlClient替代已弃用的System.Data.SqlClient,.NET 6推荐使用前者,兼容性更好。
内容的提问来源于stack exchange,提问作者Nikita Kalimov
相关产品推荐
相关产品推荐

