我的探查器跟踪显示在每个sql批处理或过程调用之间调用exec sp_reset_connection
。有reasons for it,但如果我确信没必要,可以阻止它被调用,以提高性能吗?
更新: 我认为这可以提高性能的原因有两个:
exec sp_reset_connection
,等待响应,然后发送它真正想要执行的任何sql。第二个好处是我感兴趣的一个,因为在我的架构中,客户端有时与数据库有一定距离。如果每个sql批处理或rpc都需要双向往返,则会使任何网络延迟的影响加倍。消除这种双重调用可能会提高性能。
是的,我可以做很多其他事情来提高性能,比如重新构建应用程序,我是解决问题根本原因的忠实粉丝,但在这种情况下我只是想知道它是否< em>可能以防止调用sp_reset_connection。然后我可以测试是否有任何性能改进,并正确评估不要调用它的风险。
这提示了另一个问题:与sp_reset_connection的网络通信是否真的如上所述?即客户端是否发送exec sp_reset_connection
,等待响应,然后发送真正的sql?或者这一切都在一块?
答案 0 :(得分:8)
如果您使用.NET连接到SQL Server,则从.NET 3.5开始禁用额外的重置调用 - 请参阅here。 (该财产仍然存在,但它什么也没做。)
我想微软意识到(正如有人做过实验here),打开大门以避免重置比获得(可能)小的性能增益要危险得多。不能说我责备他们。
客户端是否发送
exec sp_reset_connection
,等待响应,然后发送真正的sql?
编辑:我错了 - 请参阅here - 答案是否定的。
摘要: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的连接池。如果你打算这样做,你可能想要建立自己的连接池机制,因为只要将其关闭而不做任何其他事情可能会比获得额外往返的更多伤害,并且你将拥有手动处理正确性问题。
答案 1 :(得分:2)
就个人而言,我会离开它。
鉴于它的作用,我想确保我没有范围内的临时表或交易未完成。
公平地说,如果不对生产数据库运行探查器,您将获得更大的性能提升。你有什么数字,文章或建议可以从中得到什么?
答案 2 :(得分:2)
此Q / A可能会有所帮助: What does "exec sp_reset_connection" mean in Sql Server Profiler?
但是,我使用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.由2011年12月20日下午2:18:23创建的sa ...(2560183 ticks)。 关闭连接时间浪费:0滴答。
打开连接时间浪费:0滴答。 584.由2011年12月20日下午2:18:20创建的sa ...(1730173 ticks)。 关闭连接时间浪费:0滴答。
打开连接时间浪费:0滴答。 583.由2011年12月20日下午2:18:17创建的sa ...(710071 ticks)。 关闭连接时间浪费:0滴答。
打开连接时间浪费:0滴答。 582.由2011年12月20日下午2:18:14创建的sa ...(720072 ticks)。 关闭连接时间浪费:0滴答。
打开连接时间浪费:0滴答。 581.由2011年12月20日下午2:18:09创建的sa ...(740074 ticks)。 关闭连接时间浪费:0滴答。
所以,最后的结论是:不要担心“exec sp_reset_connection”!它什么都没浪费。
答案 3 :(得分:0)
只需保持连接打开而不是将其返回到池中,并在该连接上执行所有命令。