2012-01-04 2 views
3

問題があり、解決方法がわかりません。あなたがList<int>を持っていて、SQLデータテーブル内の約100万レコードのテーブルのIDと一致する約6000の一意のIDを持っているとします。私は私のC#プログラムからLINQ経由でそれらのIDに一致するそれらの6000レコードを選択したいと思います。私はContains()を使用したくないです。翻訳が非常に遅くなり、引数リストが大きくなるからです。LINQ - WHERE句で約6000個の固有レコードを照会します。

これを解決する方法は他にありますか?


私のシナリオについての何か(これは本当のが、同様のシナリオではありません):

私はデータベースに接続されているサービスを持っています。クライアントは、例えば、人物のようなアイテムのバッチを要求する。サービスは要求を受け入れ、DBに照会し、データをクライアントに送り返します。

人=(PERSONID、Prename、姓)

今、クライアントは人の一時的なリストを保持しています。追加の方法で、これらの人物の住所をサービスから取得したいと考えています。だから、PersonIDのリストをサービスに付け加えて、それらの人物への参照を持つ住所のリストを返すべきです。

+1

IDのサブセットは連続する可能性がありますか?例えば[1-5,10-12,14,19-32] – dtb

+0

あなたのIDを送信する必要がないように、クエリを言い換える方法はありますか?(ジョインやサブクエリがそうであるようにあなたは6,000 IDをサーバー上で解決することができますか?) – JMarsch

+0

これらのIDを別のテーブルから選択すると、SQLストアドプロシージャを作成してこれらのIDを使用し、ストアドプロシージャの結果をクライアントに返すのはいかがですか? –

答えて

3

あなたが内部使用することができますエンティティフレームワーク(EF)を使用している場合は、あなたのデータとの間の(データ)に参加し、あなたのテーブル(顧客)

void Main() 
{  
    var data = Enumerable.Range(1, 6000); 

    var result = from x in data 
    join y in Customers 
    on x equals y.CustomerID 
    select x; 

    result.Dump(); 
} 
+0

私は確かにEFを使用しています。これが本当にうまくいくなら、それは素晴らしいことでしょう!私は以前にも同じような解決策をすでに読んだと思う。私はこれを試してみます – KroaX

+0

私が提供したコードは動作しています、私はちょうどLINQPadからそれを走らせました。 –

+0

それは技術的にどのように機能するか知っていますか? SQLコマンドはどのように見えますか? – KroaX

5

私はこれをお勧めしません。 LINQの優れたツールとして、データをコードサイドで処理してスマートにしようとすると、アプリケーションのパフォーマンスに非常に悪影響を与える可能性があるシナリオがいくつかあります。

これらのIDのリストがデータベースにある場合は、ストアドプロシージャとして操作全体を実行せずに結果を返すだけで、高価なクエリをプッシュする必要はありませんすべてのデータをデータベースに保存するので、トラフィックを最小限に抑え、応答性を向上させることができます。

6000個のアイテムは、これを気にするのはあまり気にならないかもしれませんが、現実的に言えば、サイズのデータ​​セットで選択をしようとすると、パフォーマンスの悪夢となることがあります。

+1

既にデータベースに入っている場合は、そのテーブル/ p​​rocをLINQモデルで公開し、そのテーブルに「参加」するだけです。それはあなたが探している合併した結果を得るでしょう。もしそうでなければ - 私はMatthewに同意します - テーブル変数をロードするためのカスタム手続きとSQLでの結合を手作業で行うのはおそらくもっと良いでしょう。 – jklemmack

3

いくつかのアイデア:

一時テーブルに6000個のIDを挿入し、百万のレコード1にその一時テーブルに参加。

Contains()を使用し、6000のすべてではなく、N = 500,1000などのバッチを一度に選択します。

Contains()を使用すると、非常に大きなSQL文を作成するためにlinqを作成します。

+0

あなたはそれを+1します。私たちはずっと前に(バッチを使って)ADO.netと同様のテクニックを使用しなければなりませんでした。当時、私たちはいくつかの実験を行いました。バッチ内の1,000項目がティッピングポイントであることがわかりました(OracleまたはSQL Serverのいずれかを覚えていないことがあります)。引数リストを1,000以下にしておけば、パフォーマンスはかなり良いものでした。一度に1,000を大幅に下回った。 – JMarsch

+0

"table"と言うと、SQL tempテーブル、またはC#オブジェクトのリストを意味しますか? SQLエンドでこれを行うことを提案している場合は、これを行う集合理論の利点を失うことはありませんか?私はLINQがこのような負荷の下で緊張しているのを見ることができますが、SQLエンジンは大規模なセットクエリに最適化されています... – CamronBute

+0

@JMarsch - 私たちはそれを発見する苦労もありました。私が作成した動的SQL(pre-linq)に取り組んだ1つのアプリケーションと、contains節の一部が非常に大きくなったり、最終的にはメモリが足りなくなりました。クエリのメモリ使用量を一時的なストップギャップの指標として増やすことはできますが、最終的には一時テーブルを使用して限界を乗り越えて再設計しました。 –

1

通常、xmlはIDのIN基準が大きい場合に最適です。また、LINQでContainsを実行するとヒットするSQL Serverの2100の最大パラメータを取得します。

私がお勧めします:

  • メイク一覧
  • に抽出するために、あなたのストアドプロシージャの使用XPathを持つパラメータ
  • としてXMLを取るContainsXYZというストアドプロシージャを作成
  • をXMLにシリアル化をあなたがEntity Frameworkを使用していると仮定すると、このストアドプロシージャをマップして実行し、その結果を正規のエンティティにマテリアライズすることができます。
+0

XMLパーサがカンマまたはスペースで区切られた文字列の解析と比較して、パラメータから配列を読み込む最速の方法であることを確認できます。 –

0

だけの方法のうち、これを取得するには...

var joinTry = from company in dc.Companies 
       join id in list on company.CompanyID equals id 
       select company; 

動作しません。 LinqToSqlは参加できません。 "ローカルシーケンスは、Contains演算子以外のクエリ演算子のLINQからSQLへの実装では使用できません。

var containsTry = from company in dc.Companies 
        where list.Contains(company.CompanyID) 
        select company; 

予測可能

SELECT [t0].[CompanyID], [t0].[CompanyName] 
FROM [Company] AS [t0] 
WHERE [t0].[CompanyID] IN (@p0, @p1, @p2, @p3, @p4, @p5, ... 

ように...これがある限り、汚れ、SQLサーバーへのintのリストを取得するには何より高速な方法は真剣ありません。任意の呼び出しのオーバーヘッド時間は、どの解析よりも大きくなります。

SELECT 
    c.CompanyId, 
    c.CompanyName 
FROM Company c 
    WHERE CompanyID IN (1,2,3,4,5,6,7,8,9,10) 

は...

exec sp_executesql N'SELECT [t0].[CompanyID], [t0].[CompanyName] 
FROM [Company] AS [t0] 
WHERE [t0].[CompanyID] IN (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9)',N'@p0 int,@p1 int,@p2 int,@p3 int,@p4 int,@p5 int,@p6 int,@p7 int,@p8 int,@p9 int',@p0=1,@p1=2,@p2=3,@p3=4,@p4=5,@p5=6,@p6=7,@p7=8,@p8=9,@p9=10 

(LINQによって生成される)...と同じ実行速度です...と同じ速度の二倍である...

SELECT 
    c.CompanyId, 
    c.CompanyName 
FROM Company c 
     /* @Test is a table variable with 1-10 in it */ 
    INNER JOIN @Test t ON t.ID = c.CompanyID 

実際には、SQLサーバーの整数リストの処理を最適化する必要はありません。 IN()ソリューションでは、SQLはその整数をいつでも生成するインデックスに入れます。

本当の質問は...「6000の整数のリストを使って何を表していますか?」そして "私はこのリストをテーブルに入れますか?"クライアント側の6000個の整数リストを取得してサーバーに送信するソリューションは、Contains()を使用するソリューションよりもオーバーヘッドでオーバーヘッドになります。 LinqToSQLを使用する場合、あなたはある程度パラダイムに売り切れなければなりません。

これでも気にならない場合は、任意の制限リスト用のテーブルを作成してみてください。 2つの列、両方のint。次に、そのテーブルにあなたのIDを挿入して使用することができます。

var searchTry = from company in dc.Companies 
       join search in dc.SearchLists on company.CompanyID equals search.ValueID 
       where search.SearchID == savedSearchID 
       select company; 
+0

あなたの前提は間違っています。あなたの最初のケースは機能しますが、あなたは他の方向にそれをしなければなりません。 id from list dc.companyのidにcompanysに参加すると、companys.idと同じです。 select companys; – KroaX

+0

@KroaX、いいえ、あなたは間違っています! DBからすべてのレコードを選択するのではなく、SQLへの変換を使用する場合は、EFデータセットを使用してLINQ式を開始してから他のものに結合します。あなたのリストから選択し、EF DbSetに参加すると、すべてのレコードを強制的に選択します! –