大きく分けて2つのオプションがあります。
.Any
別の方法で置き換えることができます.Contains
。
- table-valued-parametersでプレーンSQLを使用できます。
使用すると実装が簡単になり、インラインSQL句.Contains
に変換されるため、パフォーマンスが向上します。IN
したがって、100の町が問題になることはありません。ただし、正確なSQLは町の正確な数に依存することも意味します。つまり、sql-serverに町の数ごとにクエリを再コンパイルするように強制します。クエリが複雑な場合、これらの再コンパイルにはコストがかかる可能性があります。また、キャッシュから他のクエリプランを削除することもできます。
table-valued-parametersを使用するのがより一般的な解決策ですが、特にSQLクエリを自分で作成する必要があり、エンティティフレームワークに依存できないため、実装するのに手間がかかります。(ObjectContext.Translate
SQLを記述している場合でも、を使用すると、クエリ結果を厳密に型指定されたオブジェクトに解凍できます)。残念ながら、エンティティフレームワークを使用して、SQLサーバーに大量のデータを効率的に渡すことはまだできません。エンティティフレームワークは、テーブル値パラメーターも一時テーブルもサポートしていません(ただし、これは一般的に要求される機能です)。
TVPsqlのビットは次のようになりselect ... from ... join @townTableArg townArg on townArg.town = address.town
ますselect ... from ... where address.town in (select town from @townTableArg)
。
おそらくEF制限を回避することはできますが、高速ではなく、おそらく注意が必要です。回避策は、値を中間テーブルに挿入し、それと結合することです。これは100回の挿入ですが、これらは別個のステートメントです。EFの将来のバージョンがバッチCUDステートメントをサポートする場合、これは実際には合理的に機能する可能性があります。
テーブル値パラメーターとほぼ同等は、一時テーブルに一括挿入し、クエリで結合することです。ほとんどの場合、これは、テーブル名が「@」ではなく「#」で始まることを意味します:-)。一時テーブルにはもう少しオーバーヘッドがありますが、インデックスを設定できます。場合によっては、後続のクエリがはるかに高速になります(非常に大量のデータの場合)。
残念ながら、一時テーブルまたはC#からの一括挿入のいずれかを使用するのは面倒です。ここでの最も簡単な解決策は、DataTable
;を作成することです。これはどちらにも渡すことができます。ただし、データテーブルは比較的低速です。数百万行を追加し始めると、オーバーが関係する可能性があります。最速の(一般的な)ソリューションは、カスタムを実装することです。IDataReader
これは、とほぼ同じ速さですIEnumerable<SqlDataRecord>
。
ちなみに、table-valued-parameterを使用するには、tableパラメーターの形状(「タイプ」)をサーバーで宣言する必要があります。一時テーブルを使用する場合は、それも作成する必要があります。
始めるためのいくつかの指針: