準備されたSQLバッチを実行するのとは別にSQLバッチを準備することは、効果的な構成です**実行計画のキャッシュ方法を考えると、SQL Serverには役に立たない。準備(解析、パラメーターのバインド、コンパイル)のステップと実行の分離は、キャッシュがない場合にのみ意味があります。目的は、既存のプランを再利用することにより、解析とコンパイルに費やす時間を節約することです。これが内部プランキャッシュの機能です。ただし、すべてのRDBMSがこのレベルのキャッシングを行うわけではないため(これらの関数の存在から明らかです)、プランを「キャッシュする」ように要求するのはクライアントコードに任されているため、そのキャッシュIDを保存して再利用しますそれ。これは、クライアントコード(およびプログラマーがそれを実行して正しく実行することを忘れないでください)に対する追加の負担であり、不要です。実際、IDbCommand.Prepare()メソッドのMSDNページには次のように記載されています。
サーバーは、必要に応じて再利用の計画を自動的にキャッシュします。したがって、クライアントアプリケーションでこのメソッドを直接呼び出す必要はありません。
テストで示されている限り(質問で表示される内容と一致する)、SqlCommand.Prepare()を呼び出すことは、「準備」のみの操作を実行しないことに注意してください。SQLを準備および実行するsp_prepexecを呼び出します。 ; 解析とコンパイルのみを行うsp_prepareを呼び出しません(そして、パラメーター値を取り込んでおらず、名前とデータ型のみを取り込んでいます)。したがって、呼び出しの「プリコンパイル」の利点はありませんSqlCommand.Prepare
すぐに実行されるません(実行を延期することが目標であると仮定)。ただし、の代わりにSqlCommand.Prepare()
呼び出す場合でも、呼び出すことの興味深い潜在的なマイナーな利点がsp_prepexec
ありsp_prepare
ます。注を参照してください(**)詳細については、下部にあります。
私のテストでは、SqlCommand.Prepare()
呼び出されたとき(およびこの呼び出しがSQL Serverでコマンドを発行しないことに注意してください)、ExecuteNonQuery
またはExecuteReader
その次が完全に実行され、ExecuteReaderの場合は行を返すことを示しています。それでも、SQL Server Profilerは、SqlCommand.Execute______()
呼び出し後の最初の呼び出しSqlCommand.Prepare()
が「SQLの準備」イベントとして登録され、その後の呼び出しが.Execute___()
として登録され呼び出しがとして登録することを示しています。
テストコード
次のURLのPasteBinにアップロードされています:http ://pastebin.com/Yc2Tfvupます。このコードは、SQL Server Profilerトレースの実行中(または拡張イベントセッション)に実行することを目的とした.NET / C#コンソールアプリを作成します。各ステップの後に一時停止するため、どのステートメントが特定の効果を持つかが明確になります。
更新
より多くの情報と、呼び出しを回避するわずかな潜在的な理由が見つかりましたSqlCommand.Prepare()
。私のテストで気づいたことの1つと、そのテストコンソールアプリを実行している人に注意すべきこと:明示的な呼び出しは行われませんsp_unprepare
。少し掘り下げて、MSDNフォーラムで次の投稿を見つけました。
SqlCommand-準備するかどうか
受け入れられた回答には多くの情報が含まれていますが、顕著なポイントは次のとおりです。
- **準備によって実際に節約できるのは、主に、クエリ文字列をネットワーク経由で送信するのにかかる時間です。
- 準備されたクエリには、キャッシュされたプランが保存される保証はなく、サーバーに到達するとアドホッククエリよりも高速ではありません。
- RPC(CommandType.StoredProcedure)は準備から何も得ません。
- サーバーでは、準備されたハンドルは基本的に、実行するTSQLを含むメモリ内マップへのインデックスです。
- マップは接続ごとに保存されるため、相互接続は使用できません。
- クライアントがプールからの接続を再利用するときに送信されるリセットにより、マップがクリアされます。
また、関連しているように見えますが、単にSqlClientがSqlConnectionの破棄時に正しくクリーンアップするのに対して、ODBCに固有の問題である可能性があるSQLCATチームからの次の投稿を見つけました。SQLCATの投稿には、接続プールのクリアなど、これを原因として証明するのに役立つ追加のテストが記載されていないため、言うのは困難です。
これらの準備されたSQLステートメントに注意してください
結論
とすれば:
- 呼び出しの唯一の本当の利点は
SqlCommand.Prepare()
、ネットワーク経由でクエリテキストを再度送信する必要がないことです。
- 接続のメモリ(つまり、SQL Serverメモリ)の一部としてクエリテキストを呼び出し
sp_prepare
てsp_prepexec
保存する
電話することをお勧めしますSqlCommand.Prepare()
唯一の潜在的な利点は、ネットワークパケットを節約することであり、一方でマイナス面はより多くのサーバーメモリを消費ため、ます。ほとんどの場合、消費されるメモリの量はおそらく非常に少ないですが、ほとんどのDBサーバーは10メガビット(最近では100メガビットまたはギガビット)接続でアプリサーバーに直接接続されているため、ネットワーク帯域幅はほとんど問題になりません(そして、いくつかは同じ箱にさえあります;-)。それとメモリはほとんどの場合、ネットワーク帯域幅よりも少ないリソースです。
複数のデータベースに接続できるソフトウェアを作成する人にとって、標準インターフェイスの利便性がこの費用/便益分析を変えるかもしれないと思います。しかし、その場合でも、基本的なオブジェクトであるため、異なるプロバイダー(したがって、呼び出す必要がないなどのプロバイダー間の違い)を可能にする「標準」DBインターフェースを抽象化するのはまだ十分に簡単であると信じる必要がありますPrepare()
おそらくあなたのアプリのコードですでに行っている指向プログラミング;-)。