2013-07-31 21 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对象混淆。如果您需要多次遍历所有项目,请将它们放入列表中。 –

相关问题