まず、パラメータ化されたSQLクエリで "IN"演算子がどのように機能するかを理解する必要があります。
SQLコマンドのパラメータが代わりにクエリが
SELECT A FROM B WHERE C IN (@p1, @p2, @p3 ... etc)
このクエリは、可変パラメータの数と、このような理由がありましたに変換され、パラメータ値としてARRAYを受け入れていない、動作しません。このクエリをIEnumerable.Contains
でプリコンパイルする方法はありません。
XmlまたはJson(Sql 2016で登場)を使用する唯一の代替方法(長い長い方法)があります。
xmlとしてIEnumerableを保存します。
[10,20,20,50] can be translated to
<data>
<int value="10"/>
<int value="20"/>
<int value="20"/>
<int value="50"/>
</data>
。しかし、あなたはその後、C IN(XMLからINT(@のP1)を選択)
B FROM
SELECT AなどのパラメータでVIEW
を定義することができますし、このビューを使用することができますこの問合せをどのように起動するかについてEFにはより多くの課題がありますが、この問合せはパラメータが1つのみであるため事前コンパイルできます。
カスタムSQLパフォーマンスハックのような非常に単純なクエリの場合
、
List<Guid> ids;
var entities = context.MyEntities.Where(x => ids.Contains(x.Id)).ToArray();
私は単純にカスタムSQLや火を使うことができ
、
var parameterList = ids.Select(
(x,i)=> new SqlCommandParameter(
"@p"+i, x));
var pnames = String.Join(",", parameterList.Select(x=> x.ParameterName));
var entities =
context.SqlQuery<MyEntity>(
"SELECT * FROM TABLE WHERE Id in (" + pnames + ")",
parameterList.ToArray());
一時表用
一時テーブルを使用することもできますが、データベース内のアクティブなトランザクションの数が増えます。
Guid sid = Guid.NewGuid();
foreach(var p in ids){
db.TempIDs.Add(new TempID{ SID = sid, Value = p });
}
db.SaveChanges();
var qIDs = db.TempIDs.Where(x=> x.SID == sid);
var myEntities db.MyEntities.Where(x => qIDs.Any(q.Value == x.Id));
// delete all TempIDs...
db.SqlQuery("DELETE FROM TempIDs WHERE [email protected],
new SqlCommandParameter("@sid", sid));
リストをパラメータとして使用することはできません。リストは、呼び出すたびに異なる要素が含まれている可能性があるため、新しいクエリを作成することを示唆しています。したがって、実際にはSQLの制限です。 –
前述のように、毎回エクスプレッションツリーを最初から解析し始めます。私たちはいくつかの結合(SQLサーバー上で数ミリ秒)を解析するために5秒かかるクエリを持っています。そのため、私は回避策を探しています。 – Roland
@rolandHowこのリストは大きいですか?また、あなたは含まれて使用するためにahveですか?問題は、各エントリーの長さによって決まります。どれくらい比較する必要があるのでしょうか。私はStringComparison.Ordinalを使用してそれをかなりスピードアップした(.Containsと比較して).Startsと同様の問題を抱えていました。問題は、大きすぎる文字列を繰り返し処理する必要があるということだけです(時間がかかります)。それをstartswithとordinalに変更することができれば、それはかなり上昇するはずです(しかし、あなたの正確なユースケースに依存します)。 – Thomas