1

私は自分のデータベースでクエリを実行する必要があります。これは、実際には100以上の検索語が存在する可能性があるこのようなものである可能性があります。

public IQueryable<Address> GetAddressesWithTown(string[] towns)
{
    IQueryable<Address> addressQuery = DbContext.Addresses;
    addressQuery.Where( x => towns.Any( y=> x.Town == y ) );
    return addressQuery;
}

ただし、約15を超える用語が含まれている場合、生成されたSQLが長すぎるため、実行時に例外がスローされます。

この種のクエリは、を介して実行できますEntity Frameworkか?

このようなクエリを完了するために利用できる他のオプションは何ですか?

4

3 に答える 3

3

申し訳ありませんが、この正確なSQLについて話しているのですか?

その場合、それは非常に単純な「目を開ける」ことです。

その文字列をIN句にマップする方法(を含む)があり、その結果、1つのSQL条件(town in(''、''、''))が発生します。

私がこれを正しく理解しているかどうかを見てみましょう:

addressQuery.Where(x => towns.Any(y => x.Town == y));

する必要があります

addressQuery.Where(x => towns.Contains(x.Town)

結果のSQLはかなり小さくなります。100個のアイテムがまだ負担になっています-ここでデータベースまたはアプリの設計の問題が発生している可能性があり、ビジネス側の分析が必要です。データベースを使用している20年間、この要件はありません。

于 2013-01-19T12:05:36.307 に答える
1

これは、 Orベースの述語を作成し、動的ラムダ式を構築するのに役立つため、 PredicateBuilderを使用するシナリオのように見えます。

これは、LinqPadを作成したJosephAlbahariによるLinqKitと呼ばれるライブラリの一部です。

 public IQueryable<Address> GetAddressesWithTown(string[] towns)
{
  var predicate = PredicateBuilder.False<Address>();

  foreach (string town in towns)
  {
    string temp = town;
    predicate = predicate.Or (p => p.Town.Equals(temp));
  }

  return DbContext.Addresses.Where (predicate);
}
于 2013-01-19T11:48:05.107 に答える
0

大きく分けて2つのオプションがあります。

  • .Any別の方法で置き換えることができます.Contains
  • table-valued-parametersでプレーンSQLを使用できます。

使用すると実装が簡単になり、インラインSQL句.Containsに変換されるため、パフォーマンスが向上します。INしたがって、100の町が問題になることはありません。ただし、正確なSQLは町の正確な数に依存することも意味します。つまり、sql-serverに町の数ごとにクエリを再コンパイルするように強制します。クエリが複雑な場合、これらの再コンパイルにはコストがかかる可能性があります。また、キャッシュから他のクエリプランを削除することもできます。

table-valued-parametersを使用するのがより一般的な解決策ですが、特にSQLクエリを自分で作成する必要があり、エンティティフレームワークに依存できないため、実装するのに手間がかかります。(ObjectContext.TranslateSQLを記述している場合でも、を使用すると、クエリ結果を厳密に型指定されたオブジェクトに解凍できます)。残念ながら、エンティティフレームワークを使用して、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パラメーターの形状(「タイプ」)をサーバーで宣言する必要があります。一時テーブルを使用する場合は、それも作成する必要があります。

始めるためのいくつかの指針:

于 2013-01-19T11:57:45.677 に答える