需要帮助从 C# 诊断 SQL 服务器奇怪的查询超时
Need help diagnosing SQL Server strange query timeouts from C#
我开发了许多 .NET / SQL 服务器应用程序,但我一直在遭受 SQL 查询超时的困扰,我无法深入了解。我在查找有问题的查询和重新索引/重写它们方面有很多经验。我的 Web 应用程序托管在 AWS 上,使用 SQL 服务器的 RDS 和 Web 应用程序的 EC2。我们每天有 100-200 个唯一用户,数据库大约 15GB,有几个表 > 1GB。
我一整天都看到异常消息:
'Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.'
发生超时的查询与超时发生的时间一样随机。它似乎与任何明显的事情都不一致(备份 运行 过夜等)。
我已经尝试从 C# 应用程序中获取每个查询并 运行 直接在 SQL 中进行查询(使用与 Arith Abort 相同的 SET 选项)并且它们都 运行 很好.有些本质上是较慢的查询,但最慢的查询 运行s 在大约 2 秒内并且具有 ~400k 逻辑读取。但是,我还看到查询在 15 毫秒内超时 运行,并且逻辑读取次数小于 10。
我见过的最奇怪的事情是我从网络应用程序中获取了一个查询并将其编码到一个控制台应用程序中,该应用程序已经 运行ning 了 24 小时,每次调用一次查询第二。它没有一个异常/超时,即使我已经看到主系统在 运行ning.
期间对同一查询有超时
我最近将 RDS 服务器升级到 M5 Large,并且每天通宵重建所有索引。我在某些时候有 运行 DBCC FREEPROCCACHE 以确保没有过时的查询计划导致问题。
我觉得这是参数嗅探,或者我最后的想法是硬件/网络故障,但这真的是抓住了救命稻草!
我得到的堆栈跟踪看起来像是在查询中,而不是在连接阶段。
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.TryReadByteArray(Byte[] buff, Int32 offset, Int32 len, Int32& totalRead)
at System.Data.SqlClient.TdsParserStateObject.TryReadString(Int32 length, String& value)
at System.Data.SqlClient.TdsParser.TryReadSqlStringValue(SqlBuffer value, Byte type, Int32 length, Encoding encoding, Boolean isPlp, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj, SqlCommandColumnEncryptionSetting columnEncryptionOverride, String columnName)
at System.Data.SqlClient.SqlDataReader.TryReadColumnInternal(Int32 i, Boolean readHeaderOnly)
at System.Data.SqlClient.SqlDataReader.TryReadColumn(Int32 i, Boolean setTimeout, Boolean allowPartiallyReadColumn)
at System.Data.SqlClient.SqlDataReader.GetValueInternal(Int32 i)
at System.Data.SqlClient.SqlDataReader.GetValue(Int32 i)
如果您能提供任何有助于查明真相的技巧,我们将不胜感激,因为它令人不安,而且我担心它会突然变得更糟。
谢谢
编辑 1
我试图通过 运行 每 10 毫秒一次测试应用程序(如上所述)并同时 运行 在 SSMS 中执行一个缓慢的阻塞事务来在本地创建相同的问题。
从应用查询
SELECT TOP 10 *
FROM MyTable
WHERE LastModifiedBy = 'Stu'
在 SSMS 中查询
BEGIN TRAN
UPDATE TOP (10000) MyTable SET LastModifiedBy = 'Me' where LastModifiedBy = 'Me'
WAITFOR DELAY '00:00:35'
COMMIT
当出现此错误时,我看到了我通常希望在 SQL Profiler 中看到的内容,其中应用程序查询恰好需要 30000 毫秒,并且我在应用程序中遇到异常。然而,有用的输出是堆栈跟踪与我在生产中看到的不同(上图)。
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
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.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
我正在读取此堆栈跟踪,因为查询从未开始执行,因为它仍在尝试读取查询的元数据。然而,这与来自生产的堆栈跟踪形成对比(在我看来)似乎是在从列中读取数据但在执行中超时。
我也一直在阅读我们正在使用的 .NET 4.6.2 版本。今晚我会将所有内容升级到 4.7.2 以排除这种情况。 (Connection to remote SQL server breaks when upgrading web server to .net framework 4.6.1)
经过一周的紧张调查,它已修复!!已经 运行 超过 2 小时了,没有一次超时:-)
原来是某种错误或与 .NET v4.6.2 不匹配。
我的配置是:
- SQL AWS RDS 上的服务器 2017 网络版
- .NET v4.6.2
- Dapper v1.50.5
我的更改是:
- 在 Web 服务器上安装 .NET 4.7.2
- 升级 Visual Studio 中的 Web 应用程序和所有 DLL 项目以使用 .NET 4.7.2(确保 web.config 已更新为
<httpRuntime targetFramework="4.7.2" />
)
- 通过 Nuget 将 Dapper 升级到最新的 v.1.60.0(我不认为 Dapper 有问题,我只是在升级它的同时做其他所有与数据库相关的事情)
这些问题帮助我指明了这个方向:
- SqlDataReader.GetValue Hangs
- ADO.Net SQLCommand.ExecuteReader() slows down or hangs
- SqlDataReader hangs on GetValue() method and SNIReadSyncOverAsync
感谢互联网 - 在你出现之前我到底是怎么编码的
我开发了许多 .NET / SQL 服务器应用程序,但我一直在遭受 SQL 查询超时的困扰,我无法深入了解。我在查找有问题的查询和重新索引/重写它们方面有很多经验。我的 Web 应用程序托管在 AWS 上,使用 SQL 服务器的 RDS 和 Web 应用程序的 EC2。我们每天有 100-200 个唯一用户,数据库大约 15GB,有几个表 > 1GB。
我一整天都看到异常消息:
'Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.'
发生超时的查询与超时发生的时间一样随机。它似乎与任何明显的事情都不一致(备份 运行 过夜等)。
我已经尝试从 C# 应用程序中获取每个查询并 运行 直接在 SQL 中进行查询(使用与 Arith Abort 相同的 SET 选项)并且它们都 运行 很好.有些本质上是较慢的查询,但最慢的查询 运行s 在大约 2 秒内并且具有 ~400k 逻辑读取。但是,我还看到查询在 15 毫秒内超时 运行,并且逻辑读取次数小于 10。
我见过的最奇怪的事情是我从网络应用程序中获取了一个查询并将其编码到一个控制台应用程序中,该应用程序已经 运行ning 了 24 小时,每次调用一次查询第二。它没有一个异常/超时,即使我已经看到主系统在 运行ning.
期间对同一查询有超时我最近将 RDS 服务器升级到 M5 Large,并且每天通宵重建所有索引。我在某些时候有 运行 DBCC FREEPROCCACHE 以确保没有过时的查询计划导致问题。
我觉得这是参数嗅探,或者我最后的想法是硬件/网络故障,但这真的是抓住了救命稻草!
我得到的堆栈跟踪看起来像是在查询中,而不是在连接阶段。
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.TryReadByteArray(Byte[] buff, Int32 offset, Int32 len, Int32& totalRead)
at System.Data.SqlClient.TdsParserStateObject.TryReadString(Int32 length, String& value)
at System.Data.SqlClient.TdsParser.TryReadSqlStringValue(SqlBuffer value, Byte type, Int32 length, Encoding encoding, Boolean isPlp, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj, SqlCommandColumnEncryptionSetting columnEncryptionOverride, String columnName)
at System.Data.SqlClient.SqlDataReader.TryReadColumnInternal(Int32 i, Boolean readHeaderOnly)
at System.Data.SqlClient.SqlDataReader.TryReadColumn(Int32 i, Boolean setTimeout, Boolean allowPartiallyReadColumn)
at System.Data.SqlClient.SqlDataReader.GetValueInternal(Int32 i)
at System.Data.SqlClient.SqlDataReader.GetValue(Int32 i)
如果您能提供任何有助于查明真相的技巧,我们将不胜感激,因为它令人不安,而且我担心它会突然变得更糟。
谢谢
编辑 1
我试图通过 运行 每 10 毫秒一次测试应用程序(如上所述)并同时 运行 在 SSMS 中执行一个缓慢的阻塞事务来在本地创建相同的问题。
从应用查询
SELECT TOP 10 *
FROM MyTable
WHERE LastModifiedBy = 'Stu'
在 SSMS 中查询
BEGIN TRAN
UPDATE TOP (10000) MyTable SET LastModifiedBy = 'Me' where LastModifiedBy = 'Me'
WAITFOR DELAY '00:00:35'
COMMIT
当出现此错误时,我看到了我通常希望在 SQL Profiler 中看到的内容,其中应用程序查询恰好需要 30000 毫秒,并且我在应用程序中遇到异常。然而,有用的输出是堆栈跟踪与我在生产中看到的不同(上图)。
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
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.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
我正在读取此堆栈跟踪,因为查询从未开始执行,因为它仍在尝试读取查询的元数据。然而,这与来自生产的堆栈跟踪形成对比(在我看来)似乎是在从列中读取数据但在执行中超时。
我也一直在阅读我们正在使用的 .NET 4.6.2 版本。今晚我会将所有内容升级到 4.7.2 以排除这种情况。 (Connection to remote SQL server breaks when upgrading web server to .net framework 4.6.1)
经过一周的紧张调查,它已修复!!已经 运行 超过 2 小时了,没有一次超时:-)
原来是某种错误或与 .NET v4.6.2 不匹配。
我的配置是:
- SQL AWS RDS 上的服务器 2017 网络版
- .NET v4.6.2
- Dapper v1.50.5
我的更改是:
- 在 Web 服务器上安装 .NET 4.7.2
- 升级 Visual Studio 中的 Web 应用程序和所有 DLL 项目以使用 .NET 4.7.2(确保 web.config 已更新为
<httpRuntime targetFramework="4.7.2" />
) - 通过 Nuget 将 Dapper 升级到最新的 v.1.60.0(我不认为 Dapper 有问题,我只是在升级它的同时做其他所有与数据库相关的事情)
这些问题帮助我指明了这个方向:
- SqlDataReader.GetValue Hangs
- ADO.Net SQLCommand.ExecuteReader() slows down or hangs
- SqlDataReader hangs on GetValue() method and SNIReadSyncOverAsync
感谢互联网 - 在你出现之前我到底是怎么编码的