通过网络从 C# .Net 应用程序运行相同的存储过程会随着每次后续执行而逐渐变慢。它似乎花费了上一次执行时间的两倍(达到最大值;请继续阅读)。执行时间逐渐变慢,直到发生 2 个场景中的一个,此时 SPROC 的第一次执行再次“快速”。
- 如果
SqlConnection
在所有测试期间打开并保持打开状态,则 SPROC 会逐渐变慢,直到运行任何其他SPROC或查询。 - 如果
SqlConnection
在每次执行前后打开和关闭一个,SPROC 会逐渐变慢,直到至少 8 分钟过去。
这只发生在少数存储过程中。一个是SELECT
带有 2 的简单查询JOINs
,(SPROC 1)另一个是 1600+ 行 SPROC (SPROC 2)。
SPROC 1的执行时间似乎永远不会超过 60 秒,而SPROC 2的执行时间似乎永远不会超过67 秒。SPROC 1初始执行时间不到一秒,SPROC 2初始执行时间为 7 秒。
这也仅在 SPROC 使用相同的应用程序运行时才会发生SqlConnection
。一旦使用了 2 个单独SqlConnection
的对象,它们的行为与上述相同,但它们是独立的。多次运行 SPROCSqlConnection1
会逐渐变慢,但第一次运行相同的 SPROC 时SqlConnection2
,它是“快的”。在 .上多次运行时,它也会变慢SqlConnection2
。
如果应用程序在安装了 SQL Server 2008 R2(运行 Windows Server 2008)的同一台计算机上运行,则不会发生这种情况。执行时间总是一致的。
在 Management Studio 中运行存储过程也不会因每次执行而变慢;它总是一致的。
清除执行计划缓存(在 SQL Server 中)对观察到的行为没有影响。
花了好几天的时间来缩小最初在更大的应用程序中观察到的问题,以便创建一个测试应用程序来轻松测试/重现它。
从我在这里阅读的内容来看,有 4 到 8 分钟的超时(SqlConnection.Close()
在代码中调用之后),此时它会关闭与数据源的数据库连接。这似乎符合我上面提到的场景 2。
这使我相信它与SqlConnection
使用的(以及与数据源的底层数据库连接)有关,因为在我的情况下启用了连接池,但是为什么我会观察到这种行为,我该如何解决呢?
我们正在使用 .Net 2.0 框架,如果这有什么不同的话。
上面列出了很多细节,所以如果我需要澄清任何事情,请告诉我。
唯一有任何相似之处的 Stack Overflow 问题是this,但与我的问题无关。
编辑: 启动时在我的 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();