IQueryable <t>到列出<t>性能问题</t> </t>

时间:2014-03-24 00:24:02

标签: c# iqueryable generic-list

我有以下代码可以正常工作,但我在性能方面遇到了一些问题。通过调试,我可以看到当代码到达下面的这一行时,需要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;
        }
    }

3 个答案:

答案 0 :(得分:1)

除装载卡车装载的数据外。 在处理方面,有一些技巧可以最大化EF上下文。 例如Context.Configuration.AutoDetectChangesEnabled = false;

您的代码段建议每次迭代都可以执行toList()。 您可能希望以不同的方式获得

List<T> queryableListdResult = queryableInitialResult.ToList();

答案 1 :(得分:0)

试试这个。我拿了你的代码并将其并行化。

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

另外,我使用了一个并发包,我相信LockLess的事情。希望这有帮助!

答案 2 :(得分:0)

请考虑您要查询的数据量。假设每篇文章只有1kB的数据。你正在拉下15k实体,你仍然试图从数据库中获取15MB的数据。假设10Mb / s的链路在数据传输速率方面10秒就完全正确。

我建议您投射查询以避免提取不必要的数据或升级数据链接。

但是,如果您需要的是您的代码更具响应性,那么您实际上可以使用流IEnumerable<T>。您只需使用DbSet<T>.AsStreaming()方法。这将在IEnumerator.Next()的每次调用中分摊数据传输的成本。但是我警告你,数据传输本身需要更长的时间,并且你将在传输的整个过程中保持一个datareader锁定。

真正更实际地阅读你的问题。你真正想要的是IQueryable.Concat。有了这个,你可以在每个IQueryable上过滤你想要的一切,然后将它们连接在一起,最后.ToList()