私はたくさんの質問を見ましたが、明らかに私のSO-fuは任務を果たせていないので、ここにいます。準備済みステートメントを効率的に使用しようとしています。単一のステートメントをパラメーター化するだけでなく、何度も再利用できるようにコンパイルすることを意味します。私の質問は、パラメーターと再利用について、そしてそれを正しく実装する方法についてです。
一般的に私はこの手順に従います(不自然な例):
_SqlConnection db = new SqlConnection(...);
SqlCommand s = new SqlCommand("select * from foo where a=@a", db);
s.Parameters.Add("@a", SqlDbType.VarChar, 8);
s.Prepare();
...
s.Parameters["@a"] = "bozo";
s.Execute();
_
スーパー、それは機能します。ただし、このクエリを実行するたびにこれらすべての手順(または後の4つ)を実行する必要はありません。それは準備されたステートメントの全体的な考えを打ち消しているようです。私の考えでは、パラメータを変更して再実行するだけでよいのですが、問題はその方法です。
私はs.Parameters.Clear()
を試しましたが、これは実際には値だけでなくパラメーター自体も削除するので、本質的にパラメーターをre _Add
とre _Prepare
を再度必要とします。これも全体のポイントを壊すようです。結構です。
この時点で、_s.Parameters
_を繰り返し処理し、すべてをnullまたはその他の値に設定することができます。 これで正しいですか?残念ながら、現在のプロジェクトには、1回の実行で約10,000回実行する必要がある〜15個のパラメーターを持つクエリがあります。このイテレーションをメソッドに振り分けることはできますが、これを行うためのより良い方法(ストアドプロシージャなし)があるかどうか疑問に思っていました。
現在の回避策は、すべてのパラメーターをnullに設定する拡張メソッド_SqlParameterCollection.Nullify
_です。これは、私の場合には問題ありません。実行後にこれを実行します。
私はいくつかの事実上同一ですが(IMHO)未回答の質問を見つけました:
SQLite/C#接続プーリングと準備済みステートメントの混乱 (Sergeは答えに非常に近かったです!)
私が見つけることができる最良の答えは、(1)上記の常識と(2)このページです。
準備されたSqlCommandを再利用する場合、確実に行う必要があるのは、パラメーター値を新しい値に設定することだけです。使用後にそれらを一掃する必要はありません。
私自身、過去10年間に作成されたDBMSでステートメントを準備することで顕著なメリットを得たことはありませんでした(DBサーバーがそのCPUの限界に達していたと思われますが、これは一般的ではありません)。準備は必要ですか?
同じコマンドを「1回の実行あたり10,000回まで」実行すると、外部ソースからアップロードしているのでない限り、少し匂いがします。その場合、一括読み込みが役立つでしょうか?それぞれの実行は何をしていますか?
乾杯-
Simonの回答に追加するには、 Sql 2005より前Command.Prepare()
は、アドホッククエリのクエリプランキャッシングを改善します(SPROCは通常コンパイルされます)。ただし、 より最近のSQLバージョン では、クエリがパラメーター化されている場合、パラメーター化されているアドホッククエリもキャッシュできるため、Prepare()
の必要性が減少します。
次に、SqlParameters
コレクションを保持して、変化するパラメーター値の値のみを変更し、パラメーターの繰り返し作成(つまり、パラメーターオブジェクトの作成とコレクションの保存)を防ぐ例を示します。
using (var sqlConnection = new SqlConnection("connstring"))
{
sqlConnection.Open();
using (var sqlCommand = new SqlCommand
{
Connection = sqlConnection,
CommandText = "dbo.MyProc",
CommandType = CommandType.StoredProcedure,
})
{
// Once-off setup per connection
// This parameter doesn't vary so is set just once
sqlCommand.Parameters.Add("ConstantParam0", SqlDbType.Int).Value = 1234;
// These parameters are defined once but set multiple times
sqlCommand.Parameters.Add(new SqlParameter("VarParam1", SqlDbType.VarChar));
sqlCommand.Parameters.Add(new SqlParameter("VarParam2", SqlDbType.DateTime));
// Tight loop - performance critical
foreach(var item in itemsToExec)
{
// No need to set ConstantParam0
// Reuses variable parameters, by just mutating values
sqlParameters["VarParam1"].Value = item.Param1Value; // Or sqlParameters[1].Value
sqlParameters["VarParam2"].Value = item.Param2Date; // Or sqlParameters[2].Value
sqlCommand.ExecuteNonQuery();
}
}
}
注: