代码之家  ›  专栏  ›  技术社区  ›  JK.

Linq分页-如何解决性能问题?

  •  2
  • JK.  · 技术社区  · 15 年前

    编辑: 实体框架似乎是一个问题,有待进一步讨论 Entity Framework & Linq performance problem .

    两条违规的线是:

    TotalItemCount = source.Count();
    

    AddRange 在此片段中:

    IQueryable<T> a = source.Skip<T>((index) * pageSize).Take<T>(pageSize);
    AddRange(a.AsEnumerable());
    

    我不明白为什么 添加范围 是这么慢还是我能做些什么来改善它?

    public class PagedList<T> : List<T>, IPagedList<T>
    {
        public PagedList(IEnumerable<T> source, int index, int pageSize)
         : this(source, index, pageSize, null)
        {
        }
    
        public PagedList(IEnumerable<T> source, int index, int pageSize, int? totalCount)
        {
            Initialize(source.AsQueryable(), index, pageSize, totalCount);
        }
    
        public PagedList(IQueryable<T> source, int index, int pageSize)
         : this(source, index, pageSize, null)
        {
        }
    
        public PagedList(IQueryable<T> source, int index, int pageSize, int? totalCount)
        {
            Initialize(source, index, pageSize, totalCount);
        }
    
        #region IPagedList Members
    
        public int PageCount { get; private set; }
        public int TotalItemCount { get; private set; }
        public int PageIndex { get; private set; }
        public int PageNumber { get { return PageIndex + 1; } }
        public int PageSize { get; private set; }
        public bool HasPreviousPage { get; private set; }
        public bool HasNextPage { get; private set; }
        public bool IsFirstPage { get; private set; }
        public bool IsLastPage { get; private set; }
    
        #endregion
    
        protected void Initialize(IQueryable<T> source, int index, 
                int pageSize, int? totalCount)
        {
            //### argument checking
            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("PageIndex cannot be below 0.");
            }
            if (pageSize < 1)
            {
                throw new ArgumentOutOfRangeException("PageSize cannot be less than 1.");
            }
    
            //### set source to blank list if source is null to prevent exceptions
            if (source == null)
            {
                source = new List<T>().AsQueryable();
            }
    
            //### set properties
            if (!totalCount.HasValue)
            {
                TotalItemCount = source.Count();
            }
            PageSize = pageSize;
            PageIndex = index;
            if (TotalItemCount > 0)
            {
                PageCount = (int)Math.Ceiling(TotalItemCount / (double)PageSize);
            }
            else
            {
                PageCount = 0;
            }
            HasPreviousPage = (PageIndex > 0);
            HasNextPage = (PageIndex < (PageCount - 1));
            IsFirstPage = (PageIndex <= 0);
            IsLastPage = (PageIndex >= (PageCount - 1));
    
            //### add items to internal list
            if (TotalItemCount > 0)
            {
                IQueryable<T> a = source.Skip<T>((index) * pageSize).Take<T>(pageSize);
                AddRange(a.AsEnumerable());
            }
        }
    }
    
    2 回复  |  直到 9 年前
        1
  •  3
  •   Josh    15 年前

    速度慢的可能不是AddRange,而是源代码上的查询。对AsEnumerable()的调用将立即返回,但实际上只有在实际枚举序列时,在AddRange调用内部才会执行查询。

    你可以通过改变这一行来证明这一点:

    AddRange(a.AsEnumerable());
    

    T[] aa = a.ToArray();
    AddRange(aa);
    

    您可能会看到ToArray()调用占用了大部分时间,因为这是实际执行查询的时间。现在谁也猜不出为什么这么慢。如果您使用的是linqtosql或实体框架,那么可以尝试分析数据库以查看瓶颈所在。但可能不是PagedList类。

        2
  •  0
  •   Robert Harvey    15 年前

    a 一个IEnumerable?那你就不用打电话了 AsEnumerable() 完全。

    尽管仔细想想,查询直到 AsEnumerable