Linq paging - как решить проблему производительности? - PullRequest
2 голосов
/ 01 сентября 2010

Редактировать: Кажется, проблема Entity Framework, обсуждается далее в вопросе Проблема производительности Entity Framework & Linq .

Я поддерживаю класс PagedList (используя linq / generics), написанный кем-то давно ушедшим - и у него 2 строки с очень плохой производительностью - для набора данных, состоящего всего из 2 тысяч строк, запуск занимает одну минуту. 1007 *

Две оскорбительные строки:

TotalItemCount = source.Count();

Я, наверное, могу это исправить, передав счет в качестве параметра. Но другая медленная строка - это AddRange в этом фрагменте:

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

Я не понимаю, почему AddRange такой медленный или что я могу сделать, чтобы улучшить его?

Полный список источников классов

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 ]

3 голосов
/ 01 сентября 2010

Вероятно, это не AddRange, который работает медленно, это, вероятно, запрос к источнику.Вызов AsEnumerable () вернется немедленно, но запрос фактически не будет выполнен до тех пор, пока внутри вызова AddRange не будет фактически перечислена последовательность.

AddRange(a.AsEnumerable());

to:

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

Вы, вероятно, увидите, что вызов ToArray () - это то, что занимает большую часть времени, потому что это когда запрос фактически выполняется.Теперь, почему это медленно, можно только догадываться.Если вы используете LINQ to SQL или Entity Framework, вы можете попробовать профилировать базу данных, чтобы увидеть узкое место.Но это, вероятно, не класс PagedList.

0 голосов
/ 01 сентября 2010

Почему бы вам просто не сделать a IEnumerable?Тогда вам вообще не придется вызывать AsEnumerable().

Хотя, если подумать, запрос фактически не выполняется до тех пор, пока не будет вызван AsEnumerable, поэтому, вероятно, он не будет иметь никакого значенияВот.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...