13

我的探查器跟踪显示exec sp_reset_connection在每个 sql 批处理或过程调用之间正在调用它。这是有原因的,但是如果我确信没有必要为了提高性能,我可以阻止它被调用吗?

更新:我认为这可以提高性能的原因是双重的:

  1. SQL Server 不需要重置连接状态。我认为这将是一个相对微不足道的改进。
  2. 减少了网络延迟,因为客户端不需要发送一个exec sp_reset_connection,等待响应,然后发送它真正想要执行的任何 sql。

第二个好处是我感兴趣的,因为在我的架构中,客户端有时与数据库有一段距离。如果每个 sql 批处理或 rpc 都需要两次往返,这会使任何网络延迟的影响加倍。消除这种双重调用可能会提高性能。

是的,我可以做很多其他的事情来提高性能,比如重新设计应用程序,我非常喜欢解决问题的根本原因,但在这种情况下,我只想知道是否可以防止 sp_reset_connection被称为。然后我可以测试是否有任何性能改进,并正确评估不调用它的风险。

这引发了另一个问题:与 sp_reset_connection 的网络通信真的像我上面概述的那样发生吗?即客户端发送exec sp_reset_connection,等待响应,然后发送真正的sql?还是全部放在一块?

4

4 回答 4

9

如果您使用 .NET 连接到 SQL Server,则从 .NET 3.5 开始禁用额外的重置调用 - 请参见此处。(该属性仍然存在,但它什么也不做。)

我猜微软意识到(就像有人在这里做实验一样)打开门来避免重置比获得(可能的)小的性能提升要危险得多。不能说我怪他们。


客户端是否发送exec sp_reset_connection,等待响应,然后发送真正的 sql?

编辑:我错了——看这里——答案是否定的。

摘要:TDS 消息中设置了一个特殊位,指定应重置连接,SQL Server 将sp_reset_connection自动执行。它在 Profiler 中显示为单独的批处理,并且始终在您要执行的实际查询之前执行,因此我的测试无效。

是的,它是分批发送的。

我整理了一个小 C# 测试程序来演示这一点,因为我很好奇:

using System.Data.SqlClient;

(...)

private void Form1_Load(object sender, EventArgs e)
{
    SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();
    csb.DataSource = @"MyInstanceName";
    csb.IntegratedSecurity = true;
    csb.InitialCatalog = "master";
    csb.ApplicationName = "blarg";

    for (int i = 0; i < 2; i++)
        _RunQuery(csb);
}

private void _RunQuery(SqlConnectionStringBuilder csb)
{
    using (SqlConnection conn = new SqlConnection(csb.ToString()))
    {
        conn.Open();

        SqlCommand cmd = new SqlCommand("WAITFOR DELAY '00:00:05'", conn);

        cmd.ExecuteNonQuery();
    }
}

启动 Profiler 并将其附加到您选择的实例,过滤我提供的虚拟应用程序名称。然后,在该行上放置一个断点cmd.ExecuteNonQuery();并运行程序。

第一次跨步时,只运行查询,在等待 5 秒后得到的只是 SQL:BatchCompleted 事件。当断点第二次命中时,您在分析器中看到的仍然只是一个事件。再次跨步时,立即看到该exec sp_reset_connection事件,然后延迟后出现 SQL:BatchCompleted 事件。

摆脱exec sp_reset_connection调用的唯一方法(这对您来说可能是也可能不是合法的性能问题)是关闭 .NET 的连接池。如果您打算这样做,您可能希望建立自己的连接池机制,因为仅将其关闭并且不做任何其他事情可能会比承受额外往返的冲击更大,而且您将拥有手动处理正确性问题。

于 2012-04-27T17:13:34.820 回答
3

此 Q/A 可能会有所帮助: Sql Server Profiler 中的“exec sp_reset_connection”是什么意思?

但是,我使用 Entity Framework 和 MS-SQL 2008 R2 进行了快速测试。它表明“exec sp_reset_connection”在第一次调用后并不耗时:

for (int i = 0; i < n; i++)
{
    using (ObjectContext context = new myEF())
    {
                
        DateTime timeStartOpenConnection = DateTime.Now;
        context.Connection.Open();
        Console.WriteLine();
        Console.WriteLine("Opening connection time waste: {0} ticks.", (DateTime.Now - timeStartOpenConnection).Ticks);

        ObjectSet<myEntity> query = context.CreateObjectSet<myEntity>();
        DateTime timeStart = DateTime.Now;
        myEntity e = query.OrderByDescending(x => x.EventDate).Skip(i).Take(1).SingleOrDefault<myEntity>();
        Console.Write("{0}. Created By {1} on {2}... ", e.ID, e.CreatedBy, e.EventDate);
        Console.WriteLine("({0} ticks).", (DateTime.Now - timeStart).Ticks);

        DateTime timeStartCloseConnection = DateTime.Now;
        context.Connection.Close();
        context.Connection.Dispose();
        Console.WriteLine("Closing connection time waste: {0} ticks.", (DateTime.Now - timeStartCloseConnection).Ticks);
        Console.WriteLine();
    }
}

输出是这样的:

打开连接时间浪费:5390101滴答。585. 由 sa 创建于 2011 年 12 月 20 日下午 2:18:23...(2560183 滴答声)。关闭连接时间浪费:0 滴答。

打开连接时间浪费:0 滴答声。584. 由 sa 创建于 2011 年 12 月 20 日下午 2:18:20...(1730173 滴答声)。关闭连接时间浪费:0 滴答。

打开连接时间浪费:0 滴答声。583. 由 sa 创建于 2011 年 12 月 20 日下午 2:18:17...(710071 滴答声)。关闭连接时间浪费:0 滴答。

打开连接时间浪费:0 滴答声。582. 由 sa 于 2011 年 12 月 20 日下午 2:18:14 创建...(720072 滴答声)。关闭连接时间浪费:0 滴答。

打开连接时间浪费:0 滴答声。581. 由 sa 于 2011 年 12 月 20 日下午 2:18:09 创建...(740074 滴答声)。关闭连接时间浪费:0 滴答。

所以,最后的结论是:不要担心“exec sp_reset_connection”!它没有浪费任何东西。

于 2012-03-08T19:37:04.700 回答
2

就个人而言,我会离开它。

鉴于它的作用,我想确保在范围内没有临时表或未打开的事务。

公平地说,通过不对生产数据库运行分析器,您将获得更大的性能提升。请问您有什么数字、文章或建议可以说明您可以从中获得什么吗?

于 2010-10-30T13:12:14.863 回答
0

只需保持连接打开而不是将其返回到池中,然后在该连接上执行所有命令。

于 2010-10-23T13:52:47.677 回答