我能停止调用sp_reset_connection来提高性能吗?

13
我的分析工具跟踪显示在每个SQL批次或过程调用之间都调用了exec sp_reset_connection。虽然有理由,但如果我确信这是不必要的,我能否阻止它的调用以提高性能?
更新: 我想这样做可以提高性能的原因有两个:
1.SQL Server不需要重置连接状态。我认为这只会带来微不足道的改进。
2.减少网络延迟,因为客户端不需要发送exec sp_reset_connection,等待响应,然后发送实际想要执行的SQL。
第二个好处才是我感兴趣的,因为在我的架构中,客户端有时与数据库相隔甚远。如果每个SQL批处理或RPC需要双倍往返,这就使任何网络延迟的影响加倍。消除这样的双重调用可能会提高性能。
是的,我还有很多其他方法可以提高性能,比如重新设计应用程序,我也很喜欢解决问题的根本原因,但在这种情况下,我只想知道是否可能防止调用sp_reset_connection。然后我可以测试是否有性能提升,并正确评估不调用此函数的风险。
这引发了另一个问题:与sp_reset_connection的网络通信是否确实像我上面概述的那样?即客户端是否发送exec sp_reset_connection,等待响应,然后发送真正的SQL?还是一次性全部发送?

1
你能描述一下你正在尝试解决的性能问题吗? - Andomar
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事件。当第二次命中断点时,Profiler中仍然只显示一个事件。再次步入时,您立即看到exec sp_reset_connection事件,然后延迟后SQL:BatchCompleted事件出现。

摆脱exec sp_reset_connection调用(这可能是您的合法性能问题)的唯一方法是关闭.NET的连接池。如果您打算这样做,您可能需要构建自己的连接池机制,因为仅仅关闭它而不采取其他措施可能会对整体造成更大的伤害,并且您将不得不手动处理正确性问题。


谢谢您的回复。然而,我认为您的测试应用程序并没有证明 exec sp_reset_connection 是在单独的批处理中发送的:它可能只是随着每个调用一起通过网络发送,除了第一个调用。我的主要关注点是这个调用是否有效地使网络延迟加倍。例如,考虑一个荒谬的情况:如果每个 SQL 批处理需要 100 毫秒运行,但网络往返需要 5000 毫秒,那么每个批处理需要 5100 毫秒还是 10100 毫秒?似乎很难创建一个好的测试来证明这一点。 - Rory
因此,答案似乎是:不能关闭 exec sp_reset_connection 而不关闭连接池,也不需要额外的服务器往返,因此不会使网络延迟对性能产生双倍影响。在某个时候,当我感到非常有精力时,我可能会使用 Wireshark 来确认它确实不会在网络上添加额外的消息往返,但是该参考和 http://msdn.microsoft.com/en-us/library/dd358342(v=prot.13) 强烈表明它不会。 - Rory

3

以下问题及答案可能会对您有所帮助: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 个ticks。 585. 创建于2011年12月20日下午2:18:23...(2560183个ticks)。 关闭连接耗时:0 个ticks。

打开连接耗时:0 个ticks。 584. 创建于2011年12月20日下午2:18:20...(1730173个ticks)。 关闭连接耗时:0 个ticks。

打开连接耗时:0 个ticks。 583. 创建于2011年12月20日下午2:18:17...(710071个ticks)。 关闭连接耗时:0 个ticks。

打开连接耗时:0 个ticks。 582. 创建于2011年12月20日下午2:18:14...(720072个ticks)。 关闭连接耗时:0 个ticks。

打开连接耗时:0 个ticks。 581. 创建于2011年12月20日下午2:18:09...(740074个ticks)。 关闭连接耗时:0 个ticks。

因此,最终结论是:不要担心“exec sp_reset_connection”!它不会浪费任何时间。

2

个人而言,我会放弃这个选项。

考虑到它的功能,我希望确保范围内没有临时表或未关闭的事务。

公正地说,如果不在生产数据库上运行分析器,您将获得更大的性能提升。请问您有任何数据、文章或建议可以说明从中获得的收益吗?


不,我没有任何数字。我想关闭它,以便我可以测量性能并获得一些数据 :) 如果有任何理由肯定不会提高性能,那也很好知道。有什么想法吗? - Rory

0

保持连接开放,而不是将其返回到池中,并在该连接上执行所有命令。


这可能是一个不错的解决方案,但需要对我的代码进行重大的重新设计,因此目前不是一个选项。 - Rory

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接