ASP.NETとSQL Server間の接続プールの問題を解決するにはどうすればよいですか?


211

過去数日間、このエラーメッセージがWebサイトに表示されすぎています。

「タイムアウトが発生しました。プールから接続を取得する前にタイムアウト期間が経過しました。これは、プールされたすべての接続が使用中であり、最大プールサイズに達したために発生した可能性があります。」

しばらくコードを変更していません。閉じていない開いている接続をチェックするようにコードを修正しましたが、すべて問題ないことがわかりました。

  • どうすればこれを解決できますか?

  • このプールを編集する必要がありますか?

  • このプールの最大接続数を編集するにはどうすればよいですか?

  • トラフィックの多いWebサイトの推奨値は何ですか?


更新:

IISで何かを編集する必要がありますか?

更新:

アクティブな接続の数は15〜31の範囲であることがわかりました。SQLサーバーで構成された接続の最大許容数は3200接続を超えている、31を超える、またはASP.NET構成で何かを編集する必要があることがわかりました?


私が正しく覚えている場合、最大プールサイズのデフォルトは100です。ほとんどのWebサイトは、高負荷時に50を超える接続を使用しません-クエリが完了するまでにかかる時間に依存します。接続文字列の短期的な修正:接続文字列に高い値を設定してみてください: "Max Pool Size = ..."
splattne

いくら?たとえば200にしますか?
Amr Elgarhy、2009年

3
問題の原因を本当に探るべきだと思います。クエリ(またはその一部)は非常に長く実行されていますか?
splattne

それが本当の理由かもしれません。クエリの実行に時間がかかります。検索します。ありがとう
Amr Elgarhy

1
問題を見つけていただければ幸いです。提案は:あなたは、SQL Serverを使用している場合は、「SQLプロファイラ」と長いクエリのを見てみてください:sql-server-performance.com/articles/per/...
splattne

回答:


218

ほとんどの場合、接続プールの問題は「接続リーク」に関連しています。あなたのアプリケーションはおそらくそのデータベース接続を正しくそして一貫して閉じません。接続を開いたままにすると、.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()閉じられていません。接続を閉じる代わりに、この行は新しい接続を作成し、それを閉じようとします。

SqlDataReaderまたはを使用する場合はOleDbDataReader、それらを閉じます。接続自体を閉じるとうまくいくように見えますが、データリーダーオブジェクトを使用するときは、明示的に閉じるように特別な努力を払ってください。


MSDN / SQL Magazineのこの記事「接続プールがオーバーフローする理由」は、多くの詳細を説明し、いくつかのデバッグ戦略を提案しています。

  • sp_whoまたはを実行しますsp_who2。これらのシステムストアドプロシージャは、sysprocessesシステムテーブルから、すべての作業プロセスのステータスと情報を示す情報を返します。通常、接続ごとに1つのサーバープロセスID(SPID)が表示されます。接続文字列でアプリケーション名引数を使用して接続に名前を付けた場合、機能している接続を簡単に見つけることができます。
  • TSQL_Replay開いている接続を追跡するには、SQL ServerプロファイラとSQLProfiler テンプレートを使用します。プロファイラーに慣れている場合、この方法はsp_whoを使用してポーリングするよりも簡単です。
  • パフォーマンスモニターを使用して、プールと接続を監視します。この方法についてはすぐに説明します。
  • コードでパフォーマンスカウンターを監視します。ルーチンを使用してカウンターを抽出するか、新しい.NET PerformanceCounterコントロールを使用して、接続プールの状態と確立された接続の数を監視できます。

4
小さな修正:GCはオブジェクトのDisposeメソッドを呼び出さず、ファイナライザ(存在する場合)のみを呼び出します。その後、ファイナライザは、必要に応じてDisposeへの「フォールバック」呼び出しを実行できますが、SqlConnectionがそうするかどうかはわかりません。
LukeH 2009年

1
最大プールサイズを50に設定する必要があり、ユーザー数が少ない場合、パフォーマンスの低下はありますか?
mahesh sharma 16

37

.NET Framework v4.6.1をインストールすると、この変更により、リモートデータベースへの接続がすぐにタイムアウトになりました

修正するにTransparentNetworkIPResolutionは、接続文字列にパラメータを追加してfalseに設定するだけです。

Server = myServerName; Database = myDataBase; Trusted_Connection = True; TransparentNetworkIPResolution = False


この場合の問題は、「プールから接続を取得する前にタイムアウト期間が経過した」ことです。接続文字列の修正でこれは解決しましたか、それとも別のハンドシェイクの問題ですか?
FBryant87 2018年

1
私が覚えていることから、それは質問とまったく同じエラーメッセージでした。.NET Framework v4.6.1にアップデートした直後に発生しました。
ajbeaven 2018年

これは私にも当てはまり、Azureで実行しているApp Service、Azure SQLデータベースへの接続で修正しました。Dapperを使用して接続を正しく破棄していましたが、「プールから接続を取得する前にタイムアウト期間が経過しました」というエラーメッセージが表示されます。しかし、これ以上はありません。ありがとう@ajbeaven
Steve Kennaird

13

使用量が大幅に増加しない限り、未処理の作業はほとんどありません。IMO、最も可能性の高いオプションは、何かが接続を使用していて、それらをすぐに解放していないことです。あなたは必ず使用しているusingすべてのケースでは?または(何らかのメカニズムを介して)接続を解放しますか?


13

接続またはデータリーダーを閉じる前に、閉じられていないDataReaderとresponse.redirectsを確認しましたか?リダイレクトの前に接続を閉じないと、接続は開いたままになります。


3
+1-またはDataReadersを返す関数-接続は、作成した関数の外側で決して閉じられません...
splattne

1
関数がSqlDataReaderを返す場合は、最大プールサイズを大きくするよりもDataTableに変換した方がよい
live-love

10

この問題は、当社のWebサイトでも時折発生します。私たちの場合の犯人は、統計/インデックスが古くなっていることです。これにより、以前は高速で実行されていたクエリが(最終的に)遅くなり、タイムアウトになります。

統計の更新やクエリの影響を受けるテーブルのインデックスの再構築を試み、それが役立つかどうかを確認してください。


3
これはクエリがタイムアウトする理由を説明すると思いますが、接続を取得しようとしているときにタイムアウトが発生する理由を説明するとは思いません。
DrGriff 2014年

1
インデックスが不適切な場合、クエリに時間がかかり、同時により多くの接続が使用される可能性があります。
LosManos

1
dbでsp_updatestatsを使用してすべての統計を更新した後、私のために働きました:EXEC sp_updatestats;
Boateng

6

接続文字列を指定MinPoolSize=xyzしたりMaxPoolSize=xyz、接続文字列を指定したりすることで、プールの最小サイズと最大サイズを指定できます。ただし、この問題の原因は別の場合があります。


3
推奨のMaxPoolSizeは?
Amr Elgarhy 2009年

2
おそらく、行くための最良の方法はありませんあなたは特別な要件を持っている、あなたはあなたのために良いプールサイズ知っている限り、それを指定するには、特定のケースを
Mehrdad Afshari、

1
注:チェックしたところ、dbへのアクティブな接続が約22のライブ接続であることがわかりました。
Amr Elgarhy 2009年

そうは思いません。デフォルトのプールサイズは100接続です。これは、ネットワークおよびSQLサーバー上の各接続の負荷に依存します。それらが重いクエリを実行している場合、問題が発生する可能性があります。また、新しい接続を開始するときにネットワークの問題が発生し、その例外が発生する可能性があります。
Mehrdad Afshari、

5

.NETアプリケーションの1つでサードパーティのデータレイヤーを使用しているときにも、この問題が発生しました。問題は、レイヤーが接続を適切に閉じなかったことでした。

レイヤーを捨てて自分で作成し、常に接続を閉じて破棄します。それ以降、エラーは発生しなくなりました。


私たちはLLBLを使用しており、ウェブサイトは2年間稼働しており、最後の数日間がこのように機能し始めました。
Amr Elgarhy 2009年

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」を使用します。


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

単純なusing(..){..}が不可能な複雑なレガシーコードに取り組んでいる場合-私のように-このSO質問に投稿したコードスニペットを確認して、接続が潜在的にリークされた場合(設定されたタイムアウト後に閉じられなかった場合)の接続作成の呼び出しスタック。これにより、リークの原因を簡単に特定できます。


2

SQL接続のインスタンス化を何度も行わないでください。1つまたは2つの接続を開き、それらを次のすべてのSQL操作に使用します。

Dispose接続を使用している場合でも例外がスローされるようです。


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();**

毎回接続を閉じたい。その前に、これが原因でエラーが発生しました。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

私が以前に遭遇したこの問題。ファイアウォールの問題になりました。ファイアウォールにルールを追加しました。1433SQLサーバーがサーバーに接続できるように、ポートを開く必要がありました。


0

これを使って:

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

12
多分私はポイントを逃していますがSqlConnection.ClearPool、それはあなたの現在の接続が解放されて接続プールに戻るのを防ぐだけですか?接続プールのアイデアは、より速い接続を可能にすることだと思いました。終了するたびにプールから接続を確実に解放するということは、プールから予備の接続をプルするのではなく、接続が必要になるたびに新しい接続を作成する必要があるということです。この手法がどのように、そしてなぜ役立つのか説明してください。
Dib 2016

0

はい、設定を変更する方法があります。専用サーバーを使用していて、さらにSQL接続が必要な場合は、次の手順に従って、両方の接続文字列の「最大プールサイズ」エントリを更新できます。

  1. リモートデスクトップを使用してサーバーにログインする
  2. マイコンピュータ(Windows-E)を開き、C:\ inetpub \ vhosts [domain] \ httpdocsに移動します
  3. web.configファイルをダブルクリックします。ファイル構造が拡張子を非表示にするように設定されている場合、これは単にWebとしてリストされる場合があります。これにより、Visual Basicまたは同様のエディターが開きます。
  4. 接続文字列を見つけます。これらは以下の例のようになります。

    "name =" SiteSqlServerを追加 "connectionString =" server =(local); database = dbname; uid = dbuser; pwd = dbpassword; pooling = true; connection lifetime = 120; max pool size = 25; ""

5. max pool size = Xの値を必要なプールサイズに変更します。

  1. web.configファイルを保存して閉じます。


0

私の場合、何百ものSQL接続を開いたままにする無限ループ(データベースから値を取得しようとするgetプロパティから)がありました。

問題を再現するには、次のことを試してください。

while (true)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        someCall(connection);
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.