データベース接続の作成-クエリは1回ですか、それともクエリごとですか?


101

現時点では、Webページが最初にロードされるときにデータベース接続を作成します。次に、ページを処理し、その接続に対してクエリを実行します。これが最善の方法ですか、クエリを実行するたびにデータベース接続を作成する必要がありますか?

ps 1つの接続を作成して使用する方が理にかなっていますが、これが他の問題を引き起こす可能性があるかどうかはわかりません。

MSSQLでC#(ASP.NET)を使用しています。

回答:


124

クエリ/トランザクションごとに作成すると、接続の「クローズ」を管理するのがはるかに簡単になります。

常識的に、開いて最後まで使用する必要がある理由がわかりますが、接続の切断やマルチスレッドの問題が発生します。したがって、次のステップは、たとえば50個の接続をプールし、それらをすべて開いたままにして、異なるプロセスに分配することです。そして、これがまさに.NETフレームワークが既にあなたのためにしていることであることがわかります

必要なときに接続を開き、終了したときに破棄すると、実際には接続が閉じられず、接続プールに戻されて再び使用されます。


あなたがそれを投稿したときにちょうどその記事を読んでいた:)ありがとう。
webnoob

2
リンクしたWebページは、SQL Serverに固有のものです。.NETは、他のデータベース(Oracle、Sqlite、MySqlなど)に接続するときに自動プーリングも提供しますか?
Briddums

@briddums-それはコネクタに依存すると思います。たとえば、.NetはMySqlコネクタを提供しません。MySqlによって作成および保守されています。そして、それが機能している間、私の経験では、以前の実装はバグフリーにはほど遠いものでした。
ツヴァイブルーメン

1
@briddums:プロバイダーアセンブリに依存します。MicrosoftのOracle実装とOracle自身の両方が接続プーリングをサポートしているのは確かです。MySqlがあることを聞いたことがあり、Spring.NETのプロバイダーがプーリングをサポートすることを期待しますが、私に尋ねるよりも、プロバイダーを直接検索するか尋ねる方が良いでしょう。
-pdr

1
ループ内であっても、クエリを開いてクエリを実行し、接続を破棄することは、1回開いてクエリをループするよりも同じくらい速く、時には高速であることを知っておく必要があります。常に廃棄してください。より安全で高速です。プールから接続を取得するオーバーヘッドを心配する必要はありません。非常に簡単です。
smdrager

38

クエリごとに1つの接続を作成するのがベストプラクティスです。データを表示する場合のベストプラクティスは、クエリに必要なすべてのデータを一度に取り込むことです。

背景情報:

.NETでは、呼び出しSqlConnection.Open()はデフォルトで常に接続プーリングを透過的に使用します(MSDNの「SQL Serverでの接続プーリングの使用」を参照)。したがって、を使用して新しい接続を取得し、完了したらOpen()呼び出すClose()だけで、.NETが正しいことを行います。

接続プーリングなしでは、実際のデータベース接続の作成には非常にコストがかかり(認証、ネットワークオーバーヘッドなど)、同時オープン接続の数は通常非常に制限されるため、クエリごとに1つの接続は非常に悪い考えです。


7
@webnoob-.NETは接続プーリングを使用するため、使用しません。その理由は、接続が閉じられたり、再割り当てされたりする可能性があるためです。そのため、接続を再利用することはお勧めできません
-Oded

11
-1答えはかなり誤解を招く。クエリごとに接続を作成することは非常に悪い考えです。おそらくあなたが意味するのは「接続プールから各クエリの新しい接続を取得する」ことですが、それは接続の作成と同じではありません。
-sleske

1
@sleske-pdrによる答えとどう違うのですか?
Oded

3
@Oded:なるほど。.NETでは、呼び出しSqlConnection.Open()は常に透過的に接続プーリングを使用します。したがって、「接続を開く」と「プールから接続を取得する」の違いはありません。私の誤解。私は質問に小さな説明を編集する自由を取り入れ、投票を取り戻しました。
-sleske

2
@ eaglei22-確かにそうすべきです(docs.microsoft.com/en-us/dotnet/framework/data/adonet/…を参照)。一般的には、あなたが順序でクエリの数を発行している場合、しかし、できるだけ早くプールに接続を返すようにしたいと思うかもしれませんあなたが提案するような接続を再利用する方がよいです。どのアプローチがあなたにとって良いかをテストし、見る必要があります(どの基準を使用するかわかりません-両方の方法をチェックし、選択したメトリックへの影響を確認してください)。
オデッド

0

これらはすべて.Netエコシステムのコンテキスト内にあることに注意してください。

開発者は、接続オブジェクトを再利用するためにコードを「最適化」したい場合があります。この質問の文脈を考えると、これはほとんどの場合間違いです。

ADO.Netには、接続プーリングと呼ばれる機能があります。新しい接続オブジェクトを作成して開くとき、実際にやっているのは、プールからの接続を要求することです。接続を閉じると、それをプールに戻します。

コードで直接使用するオブジェクトを理解することが重要です:SqlConnection、MySqlConnection、OleDbConnectioなどはすべて、ADO.Netによって管理される実際の基礎となる接続の単なるラッパーであり、ADO.Netの実際の接続ははるかに「重く」高価ですパフォーマンスの観点から。認証、ネットワーク通過、暗号化などの心配があるのは、これらの基礎となるオブジェクトであり、これらのオブジェクトは、実際に独自のコードで見るオブジェクトの少量のメモリをはるかに上回ります。

接続オブジェクトを再利用しようとすると、重要な基礎となる接続を効果的に管理するADO.Netの機能が破壊されます。大きなものを犠牲にして、小さなもので効率を上げます。

また、アプリケーションまたはhttpリクエスト全体で接続を再利用すると、他の方法で並行して実行できる可能性のある何かを誤ってシリアル化し、パフォーマンスのボトルネックになる可能性があります。これは実際のアプリケーションで見られます。

少なくとも1つのhttpリクエスト/レスポンスの期間だけ小さい接続を維持するここのWebページの例の場合、リクエストパイプラインで実行するクエリを評価することで、さらに効率を上げることができます。データベースへの個別のリクエストをできるだけ少なくします(ヒント:1つのSQL文字列で複数のクエリを送信し、DataReader.NextResult()異なるテーブルを使用またはチェックして、DataSetそれらの間を移動できます)。

言い換えれば、アプリケーションまたはhttpリクエストに対して1つの接続を再利用するという観点ではなく、クエリごとに1つの接続を考えるのではなく、データベースへの呼び出しごとに1つの接続という観点で考えてください。次に、これらのトリップの数を最小限に抑えることにより、接続の数を最小限に抑えてください。このようにして、両方の目標を達成できます。


しかし、それは最適化の1種類にすぎません。また、プログラマーの時間を最適化し、コードを効果的に再利用できます。開発者は、オープンですぐに使用できる接続オブジェクトを取得するためだけに、同じ定型コードを何度も繰り返し書きたくありません。退屈なだけでなく、プログラムにバグを導入する方法でもあります。

ただし、ここでも、一般にクエリごとに1つの接続(または往復)を使用する方が適切です。同じ定型コードの再作成を回避するために使用できる他のパターンがあります。ここに私が好きな一例がありますが、他にもたくさんあります。


私はこのパーティーに遅れていますが、この答えはいくつかの重要なポイントをカバーしていると思います:)
ジョエル・コーホーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.