如何解决ASP.NET和SQL Server之间的连接池问题?

问题描述 投票:167回答:19

最近几天我们在网站上看到这条错误消息:

“超时已到期。在从池中获取连接之前已经过了超时时间。这可能是因为所有池连接都在使用中并且达到了最大池大小。”

我们的代码暂时没有改变任何内容。我修改了代码以检查未关闭的打开连接,但发现一切都很好。

  • 我怎么解决这个问题?
  • 我需要编辑此池吗?
  • 如何编辑此池的最大连接数?
  • 高流量网站的推荐值是多少?

Update:

我需要在IIS中编辑某些内容吗?

Update:

我发现活动连接的数量在15到31之间,我发现在SQL Server中配置的最大允许连接数超过3200个连接,31个太多,或者我应该在ASP.NET配置中编辑一些东西?

.net asp.net sql-server sql-server-2005
19个回答
191
投票

在大多数情况下,连接池问题与“连接泄漏”有关。您的应用程序可能无法正确且一致地关闭其数据库连接。当你打开连接时,它们会一直被阻塞,直到.NET垃圾收集器通过调用它们的Finalize()方法为你关闭它们。

您想确保您确实关闭了连接。例如,如果.OpenClose之间的代码抛出异常,则以下代码将导致连接泄漏:

var connection = new SqlConnection(connectionString);
connection.Open();
// some code
connection.Close();                

正确的方法是:

var connection = new SqlConnection(ConnectionString);
try
{
     connection.Open();
     someCall (connection);
}
finally
{
     connection.Close();                
}

要么

using (SqlConnection connection = new SqlConnection(connectionString))
{
     connection.Open();
     someCall(connection);
}

当您的函数从类方法返回连接时,请确保在本地缓存它并调用其Close方法。您将使用此代码泄漏连接,例如:

var command = new OleDbCommand(someUpdateQuery, getConnection());
result = command.ExecuteNonQuery();
connection().Close(); 

从第一次调用getConnection()返回的连接未被关闭。此行不是关闭您的连接,而是创建一个新的并尝试关闭它。

如果你使用SqlDataReaderOleDbDataReader,请关闭它们。即使关闭连接本身似乎也可以解决问题,但在使用它们时需要额外的努力来明确地关闭数据读取器对象。


来自MSDN / SQL Magazine的这篇文章“Why Does a Connection Pool Overflow?”解释了很多细节,并提出了一些调试策略:

  • 运行sp_whosp_who2。这些系统存储过程从sysprocesses系统表返回信息,该表显示所有工作进程的状态和信息。通常,您将看到每个连接一个服务器进程ID(SPID)。如果使用连接字符串中的“应用程序名称”参数命名连接,则可以轻松找到工作连接。
  • 将SQL Server Profiler与SQLProfiler TSQL_Replay模板一起使用以跟踪打开的连接。如果您熟悉Profiler,则使用sp_who比使用轮询更容易。
  • 使用性能监视器来监视池和连接。我马上讨论这个方法。
  • 在代码中监视性能计数器。您可以使用例程提取计数器或使用新的.NET PerformanceCounter控件来监视连接池的运行状况和已建立连接的数量。

3
投票

就我而言,我没有关闭DataReader对象。

        using (SqlCommand dbCmd = new SqlCommand("*StoredProcedureName*"))
        using (dbCmd.Connection = new SqlConnection(WebConfigurationAccess.ConnectionString))
            {
            dbCmd.CommandType = CommandType.StoredProcedure;

            //Add parametres
            dbCmd.Parameters.Add(new SqlParameter("@ID", SqlDbType.Int)).Value = ID;
.....
.....
            dbCmd.Connection.Open();
            var dr = dbCmd.ExecuteReader(); //created a Data reader here
            dr.Close();    //gotta close the data reader
            //dbCmd.Connection.Close(); //don't need this as 'using' statement should take care of this in its implicit dispose method.
            }

2
投票

如果您正在处理复杂的遗留代码,其中无法使用简单的使用(..){..} - 就像我一样 - 您可能需要查看我在此SO question中发布的代码片段,以确定调用方式连接可能泄露时创建连接的堆栈(在设置超时后未关闭)。这使得很容易发现泄漏的原因。


2
投票

不要太多次实例化sql连接。打开一个或两个连接,并将它们用于所有下一个sql操作。

似乎即使在Disposeing连接时抛出异常。


2
投票

用这个:

finally
{
    connection.Close();
    connection.Dispose();
    SqlConnection.ClearPool();
}

2
投票

除了发布的解决方案....

在处理1000页遗留代码时,每次都会多次调用常见的GetRS,这是另一种解决问题的方法:

在现有的常见DLL中,我们添加了CommandBehavior.CloseConnection选项:

    static public IDataReader GetRS(String Sql)
    {
        SqlConnection dbconn = new SqlConnection(DB.GetDBConn());
        dbconn.Open();
        SqlCommand cmd = new SqlCommand(Sql, dbconn);
        return cmd.ExecuteReader(CommandBehavior.CloseConnection);   
    }

然后在每个页面中,只要关闭数据读取器,连接也会自动关闭,从而防止连接泄漏。

    IDataReader rs = CommonDLL.GetRS("select * from table");
    while (rs.Read())
    {
        // do something
    }
    rs.Close();   // this also closes the connection

2
投票

我只是遇到了同样的问题,并希望分享帮助我找到源代码的内容:将应用程序名称添加到连接字符串中,然后运行与SQL Server的打开连接

select st.text,
    es.*, 
    ec.*
from sys.dm_exec_sessions as es
    inner join sys.dm_exec_connections as ec on es.session_id = ec.session_id
    cross apply sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
where es.program_name = '<your app name here>'

1
投票

这个问题我在我的代码中。我将粘贴一些示例代码,我遇到了以下错误。从池中获取连接之前经过的超时时间。这可能是因为所有池连接都在使用中并且达到了最大池大小。

 String query = "insert into STATION2(ID,CITY,STATE,LAT_N,LONG_W) values('" + a1 + "','" + b1 + "','" + c1 + "','" + d1 + "','" + f1 + "')";
    //,'" + d1 + "','" + f1 + "','" + g1 + "'

    SqlConnection con = new SqlConnection(mycon);
    con.Open();
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = query;
    cmd.Connection = con;
    cmd.ExecuteNonQuery();
    **con.Close();**

您希望每次都关闭连接。在此之前我没有我们的密切连接由于这个我得到错误。添加关闭语句后,我已经结束了这个错误


0
投票

您已泄露了代码上的连接。您可以尝试使用来证明您正在关闭它们。

 Using (SqlConnection sqlconnection1 = new SqlConnection(“Server=.\\SQLEXPRESS ;Integrated security=sspi;connection timeout=5”)) {
                          sqlconnection1.Open();
                          SqlCommand sqlcommand1 = sqlconnection1.CreateCommand();
                          sqlcommand1.CommandText = “raiserror (‘This is a fake exception’, 17,1)”;
                          sqlcommand1.ExecuteNonQuery();  //this throws a SqlException every time it is called.
                          sqlconnection1.Close(); //Still never gets called.
              } // Here sqlconnection1.Dispose is _guaranteed_

https://blogs.msdn.microsoft.com/angelsb/2004/08/25/connection-pooling-and-the-timeout-expired-exception-faq/


0
投票

我之前遇到的这个问题。它最终成为防火墙的问题。我刚给防火墙添加了规则。我不得不打开端口1433,以便SQL服务器可以连接到服务器。


0
投票

在我的情况下,我有无限循环(从一个get属性试图从数据库中获取值),它继续打开数百个Sql连接。

while (true)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        someCall(connection);
    }
}

29
投票

安装.NET Framework v4.6.1后,我们与远程数据库的连接立即开始计时due to this change

要修复,只需在连接字符串中添加参数TransparentNetworkIPResolution并将其设置为false:

服务器= myServerName;数据库= MyDatabase的; Trusted_Connection = TRUE; TransparentNetworkIPResolution =假


13
投票

除非您的使用量增加,否则似乎不太可能存在积压的工作。 IMO,最可能的选择是某些东西正在使用连接而不是立即释放它们。你确定在所有情况下都使用using吗?或者(通过什么机制)释放连接?


13
投票

在关闭连接或datareader之前,您是否检查过未关闭的DataReader和response.redirects?在重定向之前不关闭它们时,连接会保持打开状态。


9
投票

我们也经常在我们的网站上遇到这个问题。在我们的案例中,罪魁祸首是我们的统计/指数已经过时。这导致先前快速运行的查询(最终)变得缓慢和超时。

尝试更新统计信息和/或重建受查询影响的表上的索引,看看是否有帮助。


5
投票

您可以通过在连接字符串中指定MinPoolSize=xyz和/或MaxPoolSize=xyz来指定最小和最大池大小。然而,这个问题的原因可能是另一回事。


5
投票

在我的一个.NET应用程序中使用某些第三方数据层时,我也遇到过这个问题。问题是该层没有正确关闭连接。

我们抛出了图层并自己创建了一个图层,它总是关闭并处理连接。从那时起,我们不再得到错误。


5
投票

您也可以尝试,以解决超时问题:

如果您没有将httpRuntime添加到webconfig,请在<system.web>标记中添加

<sytem.web>
     <httpRuntime maxRequestLength="20000" executionTimeout="999999"/>
</system.web>

像这样修改你的连接字符串;

 <add name="connstring" connectionString="Data Source=DSourceName;Initial Catalog=DBName;Integrated Security=True;Max Pool Size=50000;Pooling=True;" providerName="System.Data.SqlClient" />

最后使用

    try
    {...} 
    catch
    {...} 
    finaly
    {
     connection.close();
    }

3
投票

这主要是由于应用程序中未关闭连接。在连接字符串中使用“MinPoolSize”和“MaxPoolSize”。

© www.soinside.com 2019 - 2024. All rights reserved.