【问题标题】:SqlDataReader timeout exceptionSqlDataReader 超时异常
【发布时间】:2015-10-13 19:57:11
【问题描述】:

我有一些代码定期对 SQL Server 数据库运行查询并将行存储在字典中。这段代码在我们的生产环境中运行了大约 3 年。就在最近,它因未处理的异常而崩溃。出于故障排除的目的,我删除了除列读取之外的所有内容,并将所有内容包装在一个 try-catch 中。这是一个例外:

System.Data.dll 中发生了“System.Data.SqlClient.SqlException”类型的第一次机会异常 超时已过。在操作完成之前超时时间已过或服务器没有响应。

在 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException 异常,布尔 breakConnection) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 在 System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj,UInt32 错误) 在 System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult,TdsParserStateObject stateObj) 在 System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket() 在 System.Data.SqlClient.TdsParserStateObject.ReadByteArray(字节 [] 缓冲区,Int32 偏移量,Int32 长度) 在 System.Data.SqlClient.TdsParser.SkipValue(SqlMetaDataPriv md,TdsParserStateObject stateObj) 在 System.Data.SqlClient.TdsParser.SkipRow(_SqlMetaDataSet 列,Int32 startCol,TdsParserStateObject stateObj) 在 System.Data.SqlClient.SqlDataReader.CleanPartialRead() 在 System.Data.SqlClient.SqlDataReader.ReadInternal(布尔 setTimeout)

我正在使用与以下内容非常相似的东西:

// query is a simple select from 1 table, not long running by any means
string query = "SELECT col1, col2, col3, col4 FROM db.dbo.tbl_name WITH (nolock)"; //connection timeout
string query = "SELECT col1, col2, col3, col4 FROM db.dbo.tbl_name WITH (nolock) order by col1, col2"; //connection does not time out

SqlCommand command = new SqlCommand(query,connection)
SqlDataReader reader = command.ExecuteReader();

while (!reader.IsClosed && reader.Read()) {
  try {
    string test0 = reader[0].ToString();
    string test1 = reader[1].ToString();
    string test2 = reader[2].ToString();
    string test3 = reader[3].ToString();
    // here is where I would normally processes and store into dictionary
  }
  catch (Exception e){
    //make some noises
  }
}

当我使用其他方法运行查询时,它几乎立即返回(不到一秒),但为了看看会发生什么,我将 CommandTimeout 增加到 60 秒(从默认的 30 秒),这只是增加了我的程序在抛出异常之前挂起的时间。

在@frisbee 的建议下,我在查询中添加了一个 order by 子句,这会阻止连接超时。

我认为正在发生的事情是Read() 操作之一没有返回,然后导致连接超时,但我不知道是什么原因造成的。这通常发生在读取第 3 列时的某一行,但并非总是如此。查询返回不到 50k 行,有时它会通过所有行,有时只通过 15k

【问题讨论】:

  • 如果您怀疑列访问是罪魁祸首,请将其删除(出于消除目的...)。将reader.FieldCount 聚合到您的循环中的int 中,并且什么也不做(这只是为了让您以某种方式“触摸”每一行)。看看你是否还有超时。
  • 相同的结果,除了它在 Read() 上抛出异常
  • 所以现在你知道它不是列(不太可能开始)。如果这确实不是数据库问题,我会感到非常惊讶。自 3 年前以来发生了什么变化?更多数据?
  • 这不是生产修复,而是尝试使用 (nolock)。如果问题消失,那么问题很可能是锁。在表上运行 dbcc checkdb 并进行 defrag - 您可能在 SQL 端遇到数据问题。
  • 然后看看你是如何处理连接的。您是否正确处理 rdr?

标签: c# .net sql-server


【解决方案1】:

您为什么不继续将 SqlCommand 实例的 CommandTimeout 属性设置为一个较大的数字?这将使您的代码正常工作。

另一方面,您需要调试使服务器花费如此长时间才能完成工作的任何事情。您无法从 .NET 方面对此做任何事情。您必须单步执行在 SQL Server 上执行的底层代码。

【讨论】:

  • 我确实将它设置为 60 秒。但就像我说的那样,服务器并没有采取那种方式来返回结果。如果我在 sql management studio 中运行查询,查询会很快返回。我认为在迭代导致问题的结果集时,后续的 Read() 操作会超时。
  • @Frisbee 它应该能够在不到一秒的时间内修剪完这些行,更不用说 30 或 60 行了。我 确实 将超时设置得更高只是为了看看是否有任何效果,仍然抛出异常。
  • @Pete 然后看看我的评论。您有锁或数据问题吗?
【解决方案2】:

您为什么要检查阅读器是否在您的 while 循环中关闭?

尝试使用using 以确保事情得到正确处理。以下内容应该会让您顺利进行。

using (SqlConnection connection = MyDBConnection)
{
    connection.Open();
    SqlCommand command = new SqlCommand("SQL Query Here", connection) { CommandTimeout = 0 };


    using (var reader = command.ExecuteReader())
    {
        try
        {
            while (reader.Read())
            {

                string test0 = reader[0].ToString();
                string test1 = reader[1].ToString();
                string test2 = reader[2].ToString();
                string test3 = reader[3].ToString();

            }

        }
        catch (Exception e)
        {

            //Make some Noise

        }
    }
}

【讨论】:

  • 我正在检查阅读器是否已关闭,因为在捕获第一个异常后,它会循环并从已关闭的阅读器中读取...并引发另一个异常。我已经更改了代码以将整个 while 循环包装在 try/catch 块中。
  • 将命令超时设置为 0 将允许它无限保持打开状态,试一试。如果您怀疑表锁在您引入的每个表上使用 WITH (NOLOCK)。
【解决方案3】:

每隔一段时间运行一次?您是否可能共享命令?
如果您使用MARS 并共享连接 - 不要

using (SqlCommand cmd = con.CreateCommand) 
{   
    using (SqlDataReader rdr = cmd.ExecuteReader())
    {
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 2016-12-08
    • 1970-01-01
    • 2017-07-02
    • 2022-01-18
    • 2015-01-28
    • 2015-11-29
    相关资源
    最近更新 更多