[英]Need help optimizing loop with Linq
免责声明:我对linq经验不足。
我工作的任务之一就是维护一个电子商务网站。 昨天,我们的一位客户开始抱怨在尝试为Google创建供稿文件时会发生超时。 事实证明,如果用户要在其供稿文件中放入9,000多个项目,则我们的代码至少需要一分钟的时间来执行。
我无法通过运行调试器来找到问题的根源,所以我启动了探查器(ANTS)并让其执行操作。 它找到了问题的根源,一个包含一些linq代码的foreach循环。 这是代码:
var productMappings = GoogleProductMappingAccess.GetGoogleProductMappingsByID(context, productID);
List<google_Category> retCats = new List<google_Category>(numCategories);
int added = 0;
//this line was flagged by the profiler as taking 48.5% of total run time
foreach (google_ProductMapping pm in (from pm in productMappings orderby pm.MappingType descending select pm))
{
if (pm.GoogleCategoryId.HasValue && pm.GoogleCategoryId > 0)
{
//this line was flagged as 36% of the total time
retCats.Add(pm.google_Category);
}
else if (pm.GoogleCategoryMappingId.HasValue && pm.GoogleCategoryMappingId > 0)
{
retCats.Add(pm.google_CategoryMapping.google_Category);
}
else
{
continue;
}
if (++added >= numCategories)
{
break;
}
}
你们中任何较有经验的开发人员有任何想法吗? 我当时正试图用sql替换所有linq,但是我不确定这是否是最好的操作方法(如果它是用linq编写的,则一定有原因)。
如果您可以过滤出不希望出现的结果,无论如何您的查询都应该更快-您正在使用orderby
因此所有这些结果都将用完查询中的处理,因为必须对它们全部进行评估:
productMappings.Where( pm => (pm.GoogleCategoryMappingId.HasValue
&& pm.GoogleCategoryMappingId > 0)
||(pm.GoogleCategoryMappingId.HasValue &&
pm.GoogleCategoryMappingId > 0)
)
.OrderBy(...)
另外,您应该限制查询返回的结果数,因为您最多只能使用numCategories
。 所以加一个
.Take(numCategories)
而不是在foreach循环中进行检查。
retCats.Add(pm.google_Category);
的原因retCats.Add(pm.google_Category);
之所以花费这么长时间,是因为您引用的是延迟加载的对象,该对象将再次往返服务器。 如果您可以重构它,那么您只需获取Id的本地副本,而不是整个对象,这将加快这一部分的速度。
如果确实需要获取整个对象,请研究在获取productMappings时如何在单个查询中将其下拉。 如何执行此操作将取决于您在SQL上使用的LINQ包装器。
不知道您的数据库架构,这真的很难分辨。 一些想法:
1)通过数据库引擎优化顾问运行查询。 也许查询需要一些索引?
2)预处理此信息,并将其放入另一个表或文件中。 这样,当Google请求时,它不会超时。
这可能应该工作:
var productMappings = GoogleProductMappingAccess.GetGoogleProductMappingsByID(context, productID);
var categories = from pm in productMappings
where pm.GoogleCategoryId > 0 ||
pm.GoogleCategoryMappingId > 0
orderby pm.MappingType descending
select pm.google_Category ??
pm.google_CategoryMapping.google_Category;
return categories.Take(numCategories);
如果GetGoogleProductMappingsByID返回IQueryable
(如果适用),则效果最佳。 如果是这样,LINQ会将整个语句转换为T-SQL命令,这将比内存LINQ快得多。
随意在最后一条语句中添加.ToList(),使其具有与代码中相同的返回类型(并强制执行LINQ语句)。
同时检查.HasValue和> 0是没有用的。 检查Id> 0就足够了。
有关更多信息: http : //msdn.microsoft.com/zh-cn/library/2cf62fcy.aspx (运营商)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.