2013-07-31 25 views
1

這LINQ的很慢:爲什麼LINQ的慢(見提供的實施例)

IEnumerable<string> iedrDataRecordIDs = dt1.AsEnumerable() 
    .Where(x => x.Field<string>(InputDataSet.Column_Arguments_Name) == sArgumentName 
     && x.Field<string>(InputDataSet.Column_Arguments_Value) == sArgumentValue) 
    .Select(x => x.Field<string>(InputDataSet.Column_Arguments_RecordID)); 

IEnumerable<string> iedrDataRecordIDs_Filtered = dt2.AsEnumerable() 
    .Where(x => iedrDataRecordIDs.Contains(
       x.Field<string>(InputDataSet.Column_DataRecordFields_RecordID)) 
      && x.Field<string>(InputDataSet.Column_DataRecordFields_Field) 
       == sDataRecordFieldField 
      && x.Field<string>(InputDataSet.Column_DataRecordFields_Value) 
       == sDataRecordFieldValue) 
    .Select(x => x.Field<string>(InputDataSet.Column_DataRecordFields_RecordID)); 

IEnumerable<string> ieValue = dt2.AsEnumerable() 
    .Where(x => x.Field<string>(InputDataSet.Column_DataRecordFields_RecordID) 
       == iedrDataRecordIDs_Filtered.FirstOrDefault() 
      && x.Field<string>(InputDataSet.Column_DataRecordFields_Field) == sFieldName) 
    .Select(x => x.Field<string>(InputDataSet.Column_DataRecordFields_Value)); 

if (!ieValue.Any()) //very slow at this point 
    return iedrDataRecordIDs_Filtered.FirstOrDefault(); 

這種變化由10個或更多

string sRecordID = dt2.AsEnumerable() 
    .Where(x => iedrDataRecordIDs.Contains(
      x.Field<string>(InputDataSet.Column_DataRecordFields_RecordID)) 
     && x.Field<string>(InputDataSet.Column_DataRecordFields_Field) 
      == sDataRecordFieldField 
     && x.Field<string>(InputDataSet.Column_DataRecordFields_Value) 
      == sDataRecordFieldValue) 
    .Select(x => x.Field<string>(InputDataSet.Column_DataRecordFields_RecordID)) 
    .FirstOrDefault(); 

IEnumerable<string> ieValue = dt2.AsEnumerable() 
    .Where(x => x.Field<string>(InputDataSet.Column_DataRecordFields_RecordID) == sRecordID 
     && x.Field<string>(InputDataSet.Column_DataRecordFields_Field) == sFieldName) 
    .Select(x => x.Field<string>(InputDataSet.Column_DataRecordFields_Value)); 

if (!ieValue.Any()) //very fast at this point 
    return iedrDataRecordIDs_Filtered.FirstOrDefault(); 

唯一的變化的一個因素加速它的是,我將結果直接存儲在新變量中,並使用該值創建where子句而不是LINQ查詢(應在需要時計算)。但LINQ似乎在這裏計算得不好,還是我做錯了什麼?

我的數據在這裏的一些值

dt1.Rows.Count      142 
dt1.Columns.Count     3 
dt2.Rows.Count      159 
dt2.Columns.Count     3 
iedrDataRecordIDs.Count()   1 
iedrDataRecordIDs_Filtered.Count() 1 
ieValue.Count()      1 

回答

3

你問爲什麼

IEnumerable<string> iedrDataRecordIDs_Filtered = data;  
foreach (var item in collection) 
{ 
    // do something with 
    iedrDataRecordIDs_Filtered.FirstOrDefault(); 
} 

慢於

string sRecordID = data.FirstOrDefault(); 
foreach (var item in collection) 
{ 
    // do something with 
    sRecordID; 
} 

很簡單,因爲你每次評估iedrDataRecordIDs集合一次你得到FirstOrDefault。這不是一個具體的對象,它是一個可枚舉的集合。這實際上只是一個返回一些對象的函數。每次查詢它時,函數都會被調用,您將支付該執行成本。

如果更改

IEnumerable<string> iedrDataRecordIDs_Filtered = dt2.AsEnumerable()... 
var recordIDs = iedrDataRecordIDs_Filtered.ToList(); 

然後用recordIDs.FirstOrDefault()你會看到一個巨大的性能提升。

+0

所以你建議我使用ToList()創建一個List 。這不會花費太多嗎? – UNeverNo

+0

如果您只需要第一個項目,然後選擇第一個項目(您的第二個,更快的執行示例)。我認爲你需要在某個時候確定的所有項目,否則你爲什麼要創建一個「IEnumerable」? –

+0

回覆:「成本太高」 - 取決於如此多*的東西,但是如果項目已經在內存中,那麼它不會花費大量的內存 - 僅僅是參考 - 也不是時間。我的建議是專注於你需要做的事情!如果您只需要第一個項目,只需獲取第一個項目,將其放入一個局部變量,然後使用它,而不是與IEnumerable對象混淆。如果您需要多次遍歷所有項目,請將它們放入列表中。 –

相關問題