1

5,00,000 以上のレコードを持つデータテーブルで実行される LINQ クエリがあります。このクエリでは 1 行しか返されませんが、実行には約 30 秒かかります。これは私のクエリです

  var callDetailsForNodes = from records in dtRowForNode.Select().Select(dr =>
    new
    {
        caller1 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F1"] : dr["F2"],
        caller2 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F2"] : dr["F1"],
        time = dr["F3"],
        filters = dr.Field<string>("F9")
    }).Where(dr => (dtMin <= Convert.ToDateTime(dr.time)) && (dtMax >= Convert.ToDateTime(dr.time)) && (lstCallType.Contains(dr.filters))
             && (dtMinTime <= Convert.ToDateTime(dr.time).TimeOfDay) && (dtMaxTime >= Convert.ToDateTime(dr.time).TimeOfDay))
    .GroupBy(drg => new { drg.caller1, drg.caller2 })
    .Select(drg => new { drg.Key.caller1, drg.Key.caller2, count = drg.Count() }).AsEnumerable()
                                  where (records.caller1.ToString() == VerSelected || records.caller2.ToString() == VerSelected)
                                  select records;

再びクエリを実行して、上記のクエリから取得したデータを再配置します

 var callDetailsForNodes_ReArrange = from records in callDetailsForNodes.Select(r => new
        {
            caller1 = r.caller1.ToString() == VerSelected ? r.caller1 : r.caller2,
            caller2 = r.caller1.ToString() != VerSelected ? r.caller1 : r.caller2,
            count = r.count
        })
        select records;

次に、このコレクションをグリッドビューにバインドしています。このような大規模なデータセットに対してクエリを実行する効率的な方法はありますか

編集

プログラムを段階的にデバッグしようとしましたが、この2つのクエリが実際に高速に実行され、このクエリの結果セットを ObservableCollection に追加してグリッドビューにバインドするステップで時間がかかることがわかりました。ここにコードがあります

foreach (var callDetailsForNode_ReArrange in callDetailsForNodes_ReArrange)
        {

                _CallForNodes.Add(new CallForNodeData
                {
                    Caller1 = callDetailsForNode_ReArrange.caller1.ToString(),
                    Caller2 = callDetailsForNode_ReArrange.caller2.ToString(),
                    Count = callDetailsForNode_ReArrange.count
                });

        }

ここで callDetailsForNodes_ReArrange の結果セット数 = 1

4

2 に答える 2

0

役立つことの 1 つは、呼び出しの前に dtMin、dtMax、および dtMinTime をデータの単位 (dr.time) に変換することです。次に、各レコードで複数回発生している Convert.ToDateTime を取り除くことができます。

于 2013-02-07T10:50:40.263 に答える
0

クエリを少し整理しました (ただし、パフォーマンスに大きな違いはありませんが、VS を持っていないため、タイプミスがある可能性があります)。あなたの編集から、LINQ での遅延実行によって少し混乱しているようです。callDetailsForNodes結果を表すものではありません。これは、実行されると結果を提供するクエリです。

このすべてのクエリをプロセスで実行する必要がある場合はToList、最初の選択の後に a を追加して、それを単独で実行することをお勧めします。次に、句に追加ToListします。Whereを呼び出すToListと、クエリが強制的に実行され、遅延がどこにあるかがわかります。

最後の注意点 -各項目ObservableCollectionを呼び出すのではなく、レコードを直接コンストラクターに渡す必要があります。Addを呼び出すAddと (私が思うに) コレクションが変更された通知を発生させますが、これは小さなリストでは大したことではありませんが、大きなリストでは速度が低下します。

var callDetailsForNodes = dtRowForNode.AsEnumerable()
                              .Select(dr => new {
                                                    caller1 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F1"] : dr["F2"],
                                                    caller2 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F2"] : dr["F1"],
                                                    time = Convert.ToDateTime(dr["F3"]),
                                                    filters = dr.Field<string>("F9")})
                              .Where(dr => (dtMin <= dr.time) 
                                        && (dtMax >= dr.time) 
                                        && (lstCallType.Contains(dr.filters))
                                        && (dtMinTime <= dr.time.TimeOfDay) 
                                        && (dtMaxTime >= dr.time.TimeOfDay)
                                        && caller1 == VerSelected || caller2 == VerSelected))
                              .GroupBy(drg => new { drg.caller1, drg.caller2 })
                              .Select(drg => new { drg.Key.caller1, drg.Key.caller2, count = drg.Count());
于 2013-02-07T11:55:09.337 に答える