执行时间越慢,同一 SPROC 的每次迭代就越慢


通过

网络从 C# .Net 应用程序运行相同的存储过程会随着每次后续执行而逐渐变慢。它似乎花费了上一次执行的两倍时间(最高为最大值;请继续阅读)。执行时间逐渐变慢,直到发生 2 种情况中的 1 种,此时 SPROC 的第一次执行再次"快速"。

  1. 如果SqlConnection在所有测试期间都已打开并保持打开状态,在运行任何其他 SPROC 或查询之前,SPROC 会逐渐变慢。
  2. 如果在每次执行前后打开和关闭SqlConnection,则SPROC 会逐渐变慢,直到至少 8 分钟过去。

这只发生在少数存储过程中。一个是具有 2 个JOINs的简单SELECT查询 (SPROC 1),另一个是一个巨大的 1600+ 行 SPROC (SPROC 2)。

对于 SPROC 1,执行时间似乎永远不会超过 60 秒,对于 SPROC 2,执行时间似乎永远不会超过 67 秒。SPROC 1 最初执行时间不到一秒,SPROC 2 最初执行时间为 7 秒。

仅当在应用程序中使用相同的SqlConnection运行 SPROC 时,也会发生这种情况。一旦使用了 2 个单独的 SqlConnection 对象,它们的行为与上述相同,但相互独立。在SqlConnection1上多次运行 SPROC 会逐渐变慢,但第一次在SqlConnection2上运行相同的 SPROC 时,它"快"。然后,在SqlConnection2上多次运行时,它也会变慢。

如果应用程序在安装了 SQL Server 2008 R2(运行 Windows Server 2008)的同一台计算机上运行,则不会发生这种情况。执行时间始终一致。

从 Management Studio 中运行存储过程也不会随着每次执行而变慢;它始终是一致的。

清除执行计划缓存(在 SQL Server 中)对观察到的行为没有影响。

为了

创建一个测试应用程序来轻松测试/重现它,因此需要花费相当多的时间来缩小最初在更大的应用程序中观察到的此问题的范围。

从我在这里读到的内容来看,有 4 到 8 分钟的超时(在代码中调用 SqlConnection.Close() 之后),此时它会关闭与数据源的数据库连接。这似乎与我上面提到的场景 2 一致。

这让我相信它与使用SqlConnection(以及与数据源的基础数据库连接)有关,因为在我的情况下启用了连接池,但是为什么我观察到这种行为,我该如何解决它?

我们正在使用.Net 2.0框架,如果这有什么不同的话。

上面列出了许多细节,所以如果我需要澄清什么,请告诉我。

唯一有相似之处的堆栈溢出问题是这个,但与我的问题无关。

编辑:启动时,在我的 WinForms 测试应用中执行以下代码:

SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder();
connectionStringBuilder.DataSource = m_DataSource;
connectionStringBuilder.InitialCatalog = m_InitialCatalog;
connectionStringBuilder.UserID = m_UserID;
connectionStringBuilder.Password = m_Password;
connectionStringBuilder.IntegratedSecurity = false;
connectionString = connectionStringBuilder.ConnectionString;
m_DatabaseConnection = new SqlConnection(connectionString);

然后我有 2 个按钮; 其中一个调用上面提到的 SPROC 1,另一个调用不同的 SPROC,它没有相同的减速问题。以下代码在单击任一按钮时执行(唯一的区别是 SPROC 名称):

m_DatabaseConnection.Open();
m_DatabaseCommand = new SqlCommand("GetCompanies", m_DatabaseConnection);
m_DatabaseCommand.Parameters.AddWithValue("@StatusID", StatusID);
m_DatabaseCommand.CommandType = CommandType.StoredProcedure;
m_DatabaseCommand.CommandTimeout = 0;
SqlDataAdapter databaseDataAdapter = new SqlDataAdapter(m_DatabaseCommand);
DataSet databaseDataSet = new DataSet();
databaseDataAdapter.Fill(databaseDataSet);
m_DatabaseConnection.Close();

以下是我调试此问题的想法:

  • 尝试在释放连接后调用 SqlConnection.ClearAllPools()。如果这解决了问题,则问题肯定与特定连接有关。
  • 接下来,将 SPROC 包含在显式事务中。
  • 接下来,在调用 SPROC 之前调用 SqlConnection.ClearAllPools()。
  • SPROC 返回多少数据?
  • 请发布用于打开连接并执行 SPROC 的 C# 代码。
  • 创建一个独立的控制台应用,重现你所看到的行为。这将(可能)证明你的应用中的某些内容是问题所在,因为控制台应用将运行良好。

最新更新