【问题标题】:A SQL query executed well by SQL Server, but returning timeout when executed by ADO.NETSQL Server 执行良好的 SQL 查询,但在 ADO.NET 执行时返回超时
【发布时间】:2019-04-28 14:20:56
【问题描述】:

我有一台使用 ADO.NET 对 Azure SQL Server 执行 SQL 查询的服务器

当我尝试通过我的服务器(使用 ADO.NET)运行特定查询时,我收到超时错误,但是当我通过 SQL Server 执行相同的查询时,我会在 1-2 秒后获得结果。

我尝试在连接字符串和SqlCommand 对象中增加超时,但没有结果。

我看到了一种潜在的解决方案,可以将 SqlCommand 对象中的超时更改为 0,我尝试了很长时间后得到了结果,但它只适用于我的本地机器,而不适用于我的生产服务器

这是我在服务器中用于集成数据库的代码:

using (var connection = new SqlConnection(ConnectionString))
{   
    var command = new SqlCommand
    {
        CommandText = query
    };

    foreach ( var parameter in parameters)
        command.Parameters.AddWithValue(parameter.Key, parameter.Value ?? Convert.DBNull);

    command.Connection = connection;

    try
    {
        _logger.Info("Open connection to db");
        connection.Open();

        _logger.Info("Execute command");
        SqlDataReader reader = command.ExecuteReader();

        List<Column> columns = CreateColumnList(reader);
    }
    catch (Exception e)
    {
        _logger.Error(e);
    }
}

这是我收到的异常消息:

执行的超时已过期。完成操作之前超时时间已过或服务器没有响应

【问题讨论】:

  • 要在 SSMS 中运行“相同查询”,您必须使用所有参数调用 sp_executesql。使用 TSQL 局部变量或文字值将产生不同的查询计划。
  • 在发出查询后尝试监控您的数据库,看看是什么阻碍了它运行。也许它由于某种原因被锁定了。另外,我建议指定命令对象的类型,即 CommandType 属性,这样就不必推断它是文本(选择语句)还是存储过程。跨度>
  • 我建议你避免使用AddWithValue。如果列类型为 varchar,则参数类型将为带有字符串的 nvarchar,因此如果您使用 SQL 排序规则,则不会使用键列上的索引。您可能在 SSMS 查询中使用了 varchar 文字或变量。
  • @DavidBrowne-Microsoft 有点额外 - 为了获得相同的执行计划,会话还必须包含相同的 set 选项。
  • 我同意大卫的观点。您应该使用 SQL Profiler 或扩展事件来捕获在 .NET 中执行的 T-SQL。然后在此线程中粘贴两个查询。

标签: c# sql sql-server ado.net


【解决方案1】:

指定实际的列数据库类型和最大长度,而不是AddWithValue。例如:

command.Parameters.Add(parameter.Key, SqlDbType.VarChar, 30).Value = parameter.Value ?? Convert.DBNull);

这种做法将确保参数类型和长度与基础列的匹配,并有助于查询有效地使用索引。 A big problem with AddWithValue 是它会用字符串推断数据类型 nvarchar,这将防止 SARGable 表达式针对具有 SQL 排序规则的 varchar 列。

SSMS 查询运行速度快的原因可能是临时查询指定了 varchar 文字或变量。

【讨论】:

  • 这个问题可能是使用DataReader引起的。我们真的不知道“Creates ColumnList(reader)”试图完成什么。尽管您提供了很好的答案,但我不确定这是否能真正解决问题。最好的方法是捕获在 ADO.NET 中执行的 T-SQL 语句并将此语句粘贴到此线程中。
  • @DarkoMartinovic,我的回答是基于在ExecuteReader 期间发生超时的假设的有根据的猜测。读取器返回后不会发生超时。
  • 我喜欢您的回答,并且非常喜欢“有根据的猜测”。 IMO,最重要的是教育用户如何提问。这个问题应该重写并添加更多细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多