SqlConnectionを「開く/閉じる」か、開いたままにしますか?


121

静的メソッドを使用した単純な静的クラスにビジネスロジックを実装しています。これらの各メソッドは、呼び出されたときにSQL接続を開閉します。

public static void DoSomething(string something)
{
    using (SqlConnection connection = new SqlConnection("..."))
    {
        connection.Open();

        // ...

        connection.Close();
    }
}

しかし、接続を開いたり閉じたりしないようにすると、パフォーマンスが向上すると思います。私はOleDbConnectionクラス(SqlConnectionについては不明)を使用してかなり前にいくつかのテストを行いましたが、(私が覚えている限り)このように動作することは間違いなく役立ちました。

//pass the connection object into the method
public static void DoSomething(string something, SqlConnection connection)
{
    bool openConn = (connection.State == ConnectionState.Open);
    if (!openConn)
    {
        connection.Open();
    }

    // ....

    if (openConn) 
    {
        connection.Close();
    }
}

だから問題は-私は方法(a)と方法(b)のどちらを選ぶべきか?私は、接続プールによってパフォーマンスが節約されたという別のstackoverflow質問を読みました。まったく気にする必要はありません...

PS。これはASP.NETアプリです-接続はWebリクエスト中にのみ存在します。勝利のアプリやサービスではありません。


1
ただアドバイス:プロパティを直接DbConnection.StateChangeチェックする代わりに、イベントを使用して、接続の状態変化(およびローカルに保存される場合もあります)の変化を監視しますDbConnection.State。それはあなたのパフォーマンスコストを節約します。
デサイクロン

1
欠けている詳細の1つは、このメソッドがページ要求の一部である方法です。それが呼ばれる唯一の方法であるか、それは、私は私の応答で仮定として、多くの方法のザッツの1がページreqestに呼ばれ、それが右である答え影響します。)
デヴィッド・Martenssonから

David-このような多くのメソッドが呼び出されています:)
Alex

1
ケースAショー処分の信念の欠如:見stackoverflow.com/questions/1195829/...とMSDNの例msdn.microsoft.com/en-us/library/...
user2864740

回答:


82

オプションaに固執する

接続プーリングはあなたの友達です。


37
私見-彼は近づくべきではありません。破棄はそれを行います。
Royi Namir 2013

2
@RoyiNamir私は接続を閉じるための呼び出しがちょっと好きです。特に、初心者やコードベースの初心者向けです。より明確で読みやすいです。
edhedges 2014

27
@edhedges "using"とClose()の両方を使用すると、結局のところ、新規参入者を混乱させるだけです。彼らは「使用する」ことを利用する目的を理解するつもりはありません。代わりに「閉じる」を使用しないでください。代わりに「使用」の目的を教えます。彼らが学ぶことがより良くなり、彼らが学んだことをコードの他の部分に適用できるように。
Luis Perez

1
「Open()」を呼び出す必要がありますか?私は現在このように使用しています:using(var conn = GetConnection()){} public SqlConnection GetConnection(){return new SqlConnection(_connectionString); }
ガンダー

79

方法(a)を毎回使用します。アプリケーションのスケーリングを開始するとき、状態を処理するロジックは、そうしない場合、実際の痛みになります。

接続プールは、それが缶で言うことをします。アプリケーションのスケーリング時に何が起こるか、接続の開閉状態を手動で管理するのがどれほど難しいかを考えてみてください。接続プールは、これを自動的に処理するというすばらしい仕事をします。パフォーマンスが心配な場合は、何もブロックされないように、何らかのメモリキャッシュメカニズムを検討してください。


33

接続が終了したらすぐに常に接続を閉じてください。そうすれば、それらの基礎となるデータベース接続がプールに戻り、他の呼び出し元が使用できるようになります。接続プーリングはかなり最適化されているため、そうすることによる顕著なペナルティはありません。アドバイスは基本的にトランザクションの場合と同じです-完了したら、短くして閉じてください。

複数の接続を使用するコードの周りで単一のトランザクションを使用してMSDTCの問題が発生している場合は、さらに複雑になります。この場合、実際に接続オブジェクトを共有し、トランザクションが終了したときにのみ閉じる必要があります。

ただし、ここでは手作業で行うため、DataSets、Linq to SQL、Entity Framework、NHibernateなど、接続を管理するツールを調査することをお勧めします。


通常、すべてのメソッド呼び出し内で接続を開いたり閉じたりする必要はありません。ページ要求ごとに1回だけ閉じます。それは私が少なくとも学んだことです;)開閉には時間がかかります。
DavidMårtensson、2010

8
@David Martensson-SqlConnection.Openを呼び出しても、接続は実際には開かれず、閉じられません。ASP.NETは、接続文字列が以前に使用された接続文字列と一致すると、プールからアクティブな接続をリサイクルします。これに伴うオーバーヘッドは取るに足らないものであり、さらに「自分でやろう」とすることは、その後の使用ごとに接続がアクティブであることを確認するすべての管理タスクを想定する必要があることを意味し、複雑さとオーバーヘッドが追加されます。接続プーリングの場合、ベストプラクティスは、使用するたびに開閉することです。
Jamie Treworgy 2010

2
私の尊敬の念をもって、「常に接続を閉じる」という答えは、質問にうまく適合しません...私はそれらを閉じます。問題は、いつですか。
Alex

@David Martensson "Once for each page"は単純化しすぎています。複数のデータベースコマンドを順番に実行する場合は、それらを実行する間、接続を開いたままにしておくことができます。いったん閉じて再度開くと、わずかなオーバーヘッドが発生します。接続はプールに入り、しばらくするとプールから取得されます。
コンクリートガネット2017年

1
@David Martenssonただし、アイドル状態の接続は維持しないでください。ユーザーなどからのアクションを待っている場合は、それを閉じます。疑わしい場合は閉じてください。他の誰かが接続を終了し、それをプールしたことを期待して、できる限り遅く開きます。その後、あなたは好意を返します-できるだけ早く閉じることができます。
コンクリートガネット2017年

13

免責事項:私はこれが古いことを知っていますが、この事実を実証する簡単な方法を見つけたので、2セントの価値を入れています。

プーリングが本当に速くなると信じられない場合は、これを試してください:

以下をどこかに追加します。

using System.Diagnostics;
public static class TestExtensions
{
    public static void TimedOpen(this SqlConnection conn)
    {
        Stopwatch sw = Stopwatch.StartNew();
        conn.Open();
        Console.WriteLine(sw.Elapsed);
    }
}

今すぐにすべての呼び出しを置き換えるOpen()TimedOpen()し、プログラムを実行します。これで、接続文字列ごとに、コンソール(出力)ウィンドウに長時間実行中のオープンが1つと、非常に高速なオープンがたくさんあります。

それらにラベルを付ける場合は、new StackTrace(true).GetFrame(1) +への呼び出しに追加できますWriteLine


9

物理接続と論理接続には違いがあります。DbConnectionは一種の論理接続であり、基礎となるOracleへの物理接続を使用します。DbConnectionを閉じたり開いたりしてもパフォーマンスには影響しませんが、コードがクリーンで安定します。この場合、接続リークは発生しません。

また、dbサーバーでの並列接続に制限がある場合は、接続を非常に短くする必要があることを考慮する必要があります。

接続プールは、接続状態のチェックから解放されます-開いて使用し、すぐに閉じます。


はい、接続は接続ではありません。つまり、DbConnectionは物理接続ではありません。DbConnectionは、基礎となる物理接続を操作するためのメソッドとプロパティを提供する.NETクラスです。
コンクリートガネット2017年

残念ながら、これがすべて暗黙的に行われたことはすぐにはわかりませんでしたが、ドキュメントでは詳しく説明しています。docs.microsoft.com/en-us/dotnet/framework/data/adonet/...
オースティンSalgat

2

通常は、トランザクションごとに1つの接続を維持する必要があります(並列計算なし)

たとえば、ユーザーが課金アクションを実行する場合、アプリケーションはまずユーザーの残高を見つけて更新する必要があります。同じ接続を使用する必要があります。

ado.netに接続プールがある場合でも、ディスパッチ接続のコストは非常に低くなりますが、再利用接続の方が適しています。

アプリケーションで接続を1つだけ保持しないのはなぜですか

クエリまたはコマンドを実行すると接続がブロックされるため、アプリケーションは同時に1つのdb操作しか実行していないため、パフォーマンスがどれほど低いかがわかります。

もう1つの問題は、ユーザーが開いているだけで操作がない場合でも、アプリケーションは常に接続を維持することです。多くのユーザーがアプリケーションを開いている場合、dbサーバーは、ユーザーが接続していない間、接続ソースのすべてにコストをかけます。何でも。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.