免责声明:我对linq没什么经验。
我工作的一项任务是维护电子商务网站。昨天,我们的一位客户开始抱怨他们试图为谷歌创建供稿文件时会发生超时。事实证明,如果用户将超过9,000个项目放入其Feed文件中,我们的代码至少需要一分钟才能执行。
我无法通过运行调试器找到问题的根源,所以我启动了一个分析器(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编写的,那一定有理由)。
答案 0 :(得分:2)
如果您可以过滤掉您不想要的结果,那么您的查询应该更快 - 您正在使用orderby
因此所有这些结果都会在查询中使用处理,因为它们都必须进行评估:
productMappings.Where( pm => (pm.GoogleCategoryMappingId.HasValue
&& pm.GoogleCategoryMappingId > 0)
||(pm.GoogleCategoryMappingId.HasValue &&
pm.GoogleCategoryMappingId > 0)
)
.OrderBy(...)
此外,您应该限制查询返回的结果数量,因为您最多只使用numCategories
。所以添加一个
.Take(numCategories)
查询,而不是在foreach循环中检查。
答案 1 :(得分:1)
retCats.Add(pm.google_Category);
花费这么长时间的原因是因为你正在引用一个延迟加载的对象,它会再次往返于服务器。
如果您可以重构它,那么您只需要获取Id的本地副本而不是整个对象,它将加快该部分的速度。
如果您确实需要获取整个对象,请在获取productMappings时研究如何在单个查询中将其拉下来。如何执行此操作取决于您在SQL上使用的LINQ包装器。
答案 2 :(得分:0)
不知道你的数据库架构真的很难说。一些想法:
1)通过数据库引擎优化顾问运行查询。也许查询需要一些索引?
2)预处理此信息并将其放入另一个表或文件中。这样当谷歌请求它时它不会超时。
答案 3 :(得分:0)
这应该可行:
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和&gt; 0没用。检查ID&gt; 0就够了 有关详细信息:http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx(运营商)