2010-11-20 52 views
6

Đây là câu hỏi liên quan đến C# MVC2 Jqgrid - what is the correct way to do server side paging? nơi tôi đã hỏi và tìm cách cải thiện hiệu suất cho truy vấn trên một bảng có 2000 hàng trở lên. Hiệu suất được cải thiện từ 10 giây đến 1 giây.C# Entity Framework + LINQ - làm thế nào để bạn tăng tốc độ truy vấn chậm?

Bây giờ tôi đang cố gắng thực hiện cùng một truy vấn chính xác nơi bảng có 20.000 hàng - và truy vấn mất 30 giây. Làm cách nào để cải thiện thêm? 20 nghìn hàng vẫn không phải là một con số khổng lồ.

Một số ý tưởng có thể tôi đã là:

  • Nó có thể được cải thiện bằng cách de-bình thường hóa để loại bỏ tham gia và tổng
  • Hãy xem và truy vấn mà thay vì truy vấn và tham gia bảng
  • Don không truy vấn toàn bộ bảng, làm cho người dùng chọn một số bộ lọc trước (ví dụ: bộ lọc A | B | C .. vv)
  • Thêm chỉ mục vào các bảng
  • Cái gì khác?

Đây là hành động MVC mà mất 30 giây cho 20 ngàn hàng: (các thông số được cung cấp bởi jqGrid, nơi sidx = mà loại cột, và sord = thứ tự sắp xếp)

public ActionResult GetProductList(int page, int rows, string sidx, string sord, 
string searchOper, string searchField, string searchString) 
{ 
    if (sidx == "Id") { sidx = "ProductCode"; } 
    var pagedData = _productService.GetPaged(sidx, sord, page, rows); 
    var model = (from p in pagedData.Page<Product>() 
      select new 
      { 
       p.Id, p.ProductCode, p.ProductDescription, 
       Barcode = p.Barcode ?? string.Empty, 
       UnitOfMeasure = p.UnitOfMeasure != null ? p.UnitOfMeasure.Name : "", 
       p.PackSize, 
       AllocatedQty = p.WarehouseProducts.Sum(wp => wp.AllocatedQuantity), 
       QtyOnHand = p.WarehouseProducts.Sum(wp => wp.OnHandQuantity) 
      }); 

    var jsonData = new 
    { 
     Total = pagedData.TotalPages, Page = pagedData.PageNumber, 
     Records = pagedData.RecordCount, Rows = model 
    }; 

    return Json(jsonData, JsonRequestBehavior.AllowGet); 
} 

ProductService .GetPaged() gọi ProductRepository.GetPaged trong đó kêu gọi genericRepository.GetPaged() mà thực hiện điều này:

public ListPage GetPaged(string sidx, string sord, int page, int rows) 
{ 
    var list = GetQuery().OrderBy(sidx + " " + sord); 
    int totalRecords = list.Count(); 

    var listPage = new ListPage 
    { 
     TotalPages = (totalRecords + rows - 1)/rows, 
     PageNumber = page, 
     RecordCount = totalRecords, 
    }; 

    listPage.SetPageData(list 
     .Skip((page > 0 ? page - 1 : 0) * rows) 
     .Take(rows).AsQueryable()); 

    return listPage; 
} 

các .OrderBy() khoản sử dụng LinqExtensions để tôi có thể vượt qua trong một chuỗi thay vì một vị - có thể th đang làm chậm nó xuống?

Và cuối cùng ListPage chỉ là một lớp học cho thuận tiện gói lên các thuộc tính mà jqGrid nhu cầu phân trang:

public class ListPage 
{ 
    private IQueryable _data; 
    public int TotalPages { get; set; } 
    public int PageNumber { get; set; } 
    public int RecordCount { get; set; } 

    public void SetPageData<T>(IQueryable<T> data) 
    { 
     _data = data; 
    } 

    public IQueryable<T> Page<T>() 
    { 
     return (IQueryable<T>)_data; 
    } 
} 

GetQuery là:

public IQueryable<T> GetQuery() 
{ 
    return ObjectSet.AsQueryable(); 
} 

Tục phương pháp .OrderBy bao gồm hai phương pháp này :

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, 
    string ordering, params object[] values) 
{ 
    return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values); 
} 

public static IQueryable OrderBy(this IQueryable source, string ordering, 
    params object[] values) 
{ 
    if (source == null) throw new ArgumentNullException("source"); 
    if (ordering == null) throw new ArgumentNullException("ordering"); 
    ParameterExpression[] parameters = new ParameterExpression[] { 
     Expression.Parameter(source.ElementType, "") }; 
    ExpressionParser parser = new ExpressionParser(parameters, ordering, values); 
    IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering(); 
    Expression queryExpr = source.Expression; 
    string methodAsc = "OrderBy"; 
    string methodDesc = "OrderByDescending"; 
    foreach (DynamicOrdering o in orderings) 
    { 
     queryExpr = Expression.Call(
      typeof(Queryable), o.Ascending ? methodAsc : methodDesc, 
      new Type[] { source.ElementType, o.Selector.Type }, 
      queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters))); 
     methodAsc = "ThenBy"; 
     methodDesc = "ThenByDescending"; 
    } 
    return source.Provider.CreateQuery(queryExpr); 
} 
+0

Với chỉnh sửa, tôi rất bối rối về cách nó nhảy trở lại mã dựa trên chung, khi OrderBy đó sử dụng mã không chung chung ... bạn có thể làm rõ không? Tôi thiếu một cái gì đó hiển nhiên? –

+0

Xin lỗi tôi không chắc bạn đang hỏi gì - 'OrderBy()' này là một phương thức mở rộng được định nghĩa trong một lớp khác. –

+0

Vâng, 'GetQuery()' sẽ trả lại 'IQueryable ' (chung); 'GetQuery(). OrderBy (sidx +" "+ sord)' (sử dụng phương thức bạn hiển thị) sẽ là 'IQueryable' (không chung chung). AFAIK không có 'Bỏ qua (...)' vv * được định nghĩa * cho không chung chung ... không chắc chắn nó sẽ hoạt động như thế nào? –

Trả lời

6

Bit liên quan đến tôi là:

.Take(rows).AsQueryable() 

thực tế là bạn cần phải thêm AsQueryable() gợi ý với tôi rằng nó hiện đang IEnumerable<T>, có nghĩa là bạn có thể làm phân trang vào cuối sai của truy vấn (mang lại cách quá nhiều dữ liệu qua mạng). Nếu không có GetQuery() và tùy chỉnh OrderBy() thì khó có thể chắc chắn - nhưng như mọi khi, điều đầu tiên cần làm là để cấu hình truy vấn thông qua một dấu vết. Xem truy vấn nào được thực hiện và dữ liệu nào được trả về. EFProf có thể làm cho điều này dễ dàng, nhưng một dấu vết SQL có lẽ là đủ.

+1

+1 - cũng có một ít được biết đến với tên gọi '. {0} Logged cho thấy truy vấn SQL được thực hiện. Rất thuận tiện cho việc đăng nhập. – RPM1984

+0

Xin lỗi tôi đã bỏ lỡ, 'GetQuery()' là một lớp lót: 'return ObjectSet.AsQueryable();'. Tôi sẽ chỉnh sửa và thêm mã cho OrderBy() - Tôi không biết nguồn gốc của nó ở đâu, có thể ở đây: linqextensions.codeplex.com/ –

+0

@JK - thành thật mà nói, nó có thể đủ để bạn chỉ cần kiểm tra xem mã hoạt động nếu bạn loại bỏ '.AsQueryable()' –

Các vấn đề liên quan