IQueryable< T>List< T>性能问题
本文关键字:问题 性能 List IQueryable | 更新日期: 2023-09-27 17:51:26
我有下面的代码,工作得很好,但我有一些问题在其性能方面。通过调试,我可以看到,当代码到达下面这一行时,它花了10秒的时间来逐步完成。
List<T> queryableListdResult = queryableInitialResult.ToList();
基本上,下面的代码从数据库中的150000条记录中抓取大约15000篇文章。
谁能建议一个更好的方法来做这件事?谢谢!我的代码: public static IQueryable<T> CategoryFilter<T>(IQueryable<T> queryable, int categoryFilterCount, RenderingContext rc, bool CategoryOR, string categoriesforQuery) where T : AbstractResult
{
if (!string.IsNullOrEmpty(categoriesforQuery))
{
string[] categoriesDefined = categoriesforQuery.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
List<T> listInitialResult = new List<T>();
foreach (string TaxonomyID in categoriesDefined) //e.g. entertainment, business
{
string categoryToCompare = TaxonomyID.ToString().Replace("{", "").Replace("}", "");
queryable = queryable.Where(i => i.alltags.Contains(categoryToCompare));
List<T> queryableListdResult = queryable.ToList();
listInitialResult.AddRange(queryableListdResult);
}
if (CategoryOR)
{
return listInitialResult.AsQueryable();
}
else
{
List<T> queryableFinalResult = (listInitialResult.GroupBy(x => x._Group).Where(g => g.Count() >= categoryFilterCount)
.Select(g => g.FirstOrDefault())).ToList();
return queryableFinalResult.AsQueryable();
}
}
else
{
return queryable;
}
}
除了加载一卡车的数据。在处理这个问题时,有一些技巧可以最大化EF上下文。eg Context.Configuration.AutoDetectChangesEnabled = false;
您的代码片段表明toList()可能会在每次迭代中执行。你可能想找出另一种方法来获取
List<T> queryableListdResult = queryableInitialResult.ToList();
试试这个。我把你的代码并行化了。
public static IQueryable<T> CategoryFilter<T>(IQueryable<T> queryable1, int categoryFilterCount, RenderingContext rc, bool CategoryOR, string categoriesforQuery) where T : AbstractResult
{
if (!string.IsNullOrEmpty(categoriesforQuery))
{
string[] categoriesDefined = categoriesforQuery.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
ConcurrentBag<T> listInitialResult = new ConcurrentBag<T>();
Parallel.ForEach(categoriesDefined, (TaxonomyID) =>
{
string categoryToCompare = TaxonomyID.ToString().Replace("{", "").Replace("}", "");
var queryable = queryable.Where(i => i.alltags.Contains(categoryToCompare));
List<T> queryableListdResult = queryable.ToList();
for (int i = 0; i < queryableListdResult.Count; i++)
{
listInitialResult.Add(queryableListdResult[i]);
}
});
if (CategoryOR)
{
return listInitialResult.AsQueryable();
}
else
{
List<T> queryableFinalResult = (listInitialResult.GroupBy(x => x._Group).Where(g => g.Count() >= categoryFilterCount)
.Select(g => g.FirstOrDefault())).ToList();
return queryableFinalResult.AsQueryable();
}
}
else
{
return queryable;
}
}
加上我使用了一个并发包,我相信它是在无锁的情况下实现的。希望这对你有帮助!
请考虑您正在查询的数据量。假设每篇文章只有1kB的数据。您正在拉下15k个实体,您仍然试图从数据库中获取15MB的数据。假设一个10Mb/s的链路,10秒在数据传输速率方面是相当合适的。
我建议你投射你的查询,以避免提取不必要的数据或升级你的数据链接。
然而,如果你需要的是你的代码响应更快,你实际上可以使用流式IEnumerable<T>
。你只需要使用DbSet<T>.AsStreaming()
方法。这将在IEnumerator.Next()
的每次调用中分摊数据传输的成本。但是我警告你,数据传输本身将花费更长的时间,并且在传输的整个生命周期中,你将持有一个数据读取器锁。
把你的问题读得更透彻一些。你真正需要的是IQueryable.Concat
。这样,你就可以在每个IQueryable上过滤你想要的一切,然后将它们连接在一起,最后.ToList()
它。