2010-09-01 29 views
2

編輯:實體框架似乎是問題,在問題Entity Framework & Linq performance problem中進一步討論。Linq分頁 - 如何解決性能問題?

我支持一個長期離開的人編寫的PagedList類(使用linq/generics) - 它有2行非常糟糕的表現 - 對於只有2000行的數據集,它需要長達一分鐘的運行時間。

兩個問題的線路有:

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()); 
     } 
    } 
} 
+0

數據來自哪裏? PS:「我不明白爲什麼AddRange很慢」---「AddRange」不慢,但延遲linq表達式評估速度很慢。 – zerkms 2010-09-01 03:28:42

+0

@zerkms對不起,它的a.AsEnumerable()很慢,而不是AddRange – 2010-09-01 03:30:23

+0

@robert它被這樣調用:'var pagedModel = new PagedList (data,currentPage - 1,rowsPerPage);'PagedList inherits List ,所以'AddRange'和'this.AddRange'是一樣的。不是說我明白我的代碼100%自己 – 2010-09-01 03:33:38

回答

3

它可能不是的AddRange是緩慢的,它可能在源查詢。對AsEnumerable()的調用會立即返回,但實際上只有在序列實際枚舉時纔會執行查詢,直到AddRange調用內部爲止。

AddRange(a.AsEnumerable()); 

到:

您可以通過更改此行證明了這

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

你可能會看到ToArray的()調用是什麼需要的大部分時間,因爲這是當該查詢實際上被執行。現在爲什麼這麼慢是任何人的猜測。如果您使用LINQ to SQL或實體框架,則可以嘗試對數據庫進行分析以查看瓶頸位置。但它可能不是PagedList類。

+0

當我通過代碼時,它不會立即回來,這是一個重大的延遲。是的,它使用EF。我會啓動sql分析器,看看有什麼說的。 'data'參數只是一個簡單的EF getAll()查詢(因此不會有複雜的連接或其他錯誤導致sql性能下降) – 2010-09-01 03:40:32

+0

現在很奇怪:sql profiler顯示1958行被選中,它使得3916(即1958 * 2)單獨選擇另一個表(主子的子表)的全部內容。有沒有在那裏這些條款3916選擇 – 2010-09-01 03:57:23

+0

我應該問一個單獨的問題,因爲這似乎是一個EF問題?所有它確實是'VAR數據= _service.GetAll()',接着'data.Skip((指數)* pageSize的)。取(pageSize的)'。這應該不會有性能問題 – 2010-09-01 04:11:57

0

爲什麼不讓a成爲IEnumerable?那麼你根本不需要撥打AsEnumerable()

雖然想到它,但查詢實際上並沒有執行,直到調用AsEnumerable,所以它可能在這裏沒有任何區別。

+0

一個由IQueryable的方式從派生已經IEnumerable的IEnumerable的。我懷疑OP可能會投入AsEnumerable來嘗試隔離瓶頸。 – Josh 2010-09-01 04:53:36

+0

這是代碼正是我繼承的,因此不能說爲什麼會做到這一點。 – 2010-09-01 04:59:48