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;
        }
    }

IQueryable< T>List< T>性能问题

除了加载一卡车的数据。在处理这个问题时,有一些技巧可以最大化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()它。