2013-02-07 43 views
1

我有一個LINQ查詢運行在具有5,00,000條記錄的數據表上。此查詢只返回一行,但需要將近30秒才能運行。這是我的查詢對於大型數據集的高效LINQ查詢

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; 

那麼我這個集合只是綁定到GridView控件。 是否有這樣一個大的數據集查詢任何有效的方式

編輯

我嘗試調試一步的PROGRAMM一步,發現這2個查詢實際運行速度快,時間在步驟取當我將這個查詢的結果集添加到ObservableCollection以將其綁定到gridview時。下面是代碼

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

+1

_「是否有任何有效的方式來查詢如此大的數據集」_是的,使用數據庫! –

+0

你是否打斷了查詢,查看哪一部分最慢?例如。你可以在你的第一個'Select'之後停下來,然後調用'ToList()'。然後添加'Where'並調用'ToList()'等。這將幫助您識別導致速度最慢的部分。但是,正如蒂姆所說,這應該在數據庫中完成。 –

+0

我懷疑你可能會感到困惑。一旦你開始迭代集合,它就會執行你的查詢。 'callDetailsForNodes'只是一個查詢,直到你執行它爲止。將一個項目添加到「ObservableCollection」應該不會太慢。 –

回答

0

一兩件事,這將有助於將調用到數據的單元(dr.time)之前DTMIN,下降速率和dtMinTime轉換。然後,您可以擺脫每次記錄中多次發生的Convert.ToDateTime。

+0

我應該在哪裏做,在數據表本身,或者在我以代碼的形式獲取它時,即time = Convert.ToDateTime(dr [「F3」]) –

+0

@RajeevKumar您在評論中提供了什麼。 – Rawling

+0

@RajeevKumar在你的第一個選擇中設置'time = dr [「F3」]'。我認爲羅林提出的建議是將其改爲'time = Convert.ToDateTime(dr [「F3」])'。那樣'時間'是一個日期時間,並且不必在'Where'中多次轉換。 –

0

我整理了一下你的查詢(雖然這不會對性能產生巨大的影響,並且可能會因爲我沒有VS而發生錯別字)。從你的編輯看來,你對LINQ中的延遲執行感到有點困惑。 callDetailsForNodes不代表你的結果 - 它是一個查詢,它會在執行結果後提供你的結果。

如果你必須在進行所有這些查詢,我建議你在第一次選擇並在隔離運行之後添加ToList。然後將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());