2010-11-20 1 views
6

이 질문은 C# MVC2 Jqgrid - what is the correct way to do server side paging?과 관련된 질문이며 2000 또는 그 이상의 행이있는 테이블의 쿼리 성능을 향상시키는 방법을 찾았습니다. 성능은 10 초에서 1 초로 향상되었습니다.C# Entity Framework + Linq - 어떻게 느린 쿼리를 빠르게 할 수 있습니까?

이제 테이블에 20,000 개의 행이 있고 쿼리에 30 초가 걸리는 정확한 쿼리를 수행하려고합니다. 어떻게하면 더 향상시킬 수 있습니까? 20,000 개의 행은 여전히 ​​큰 숫자가 아닙니다.

몇 가지 가능한 아이디어 I는 한 :

조인 제거 드 정상화 향상 및
  • 는 뷰와 쿼리를 확인 요약 할 수있다
    • 대신 테이블
    • 돈을 조회 및 가입 전체 테이블을 쿼리하지 말고 사용자가 일부 필터를 먼저 선택하도록하십시오 (예 : A | B | C .. 등 필터)
    • 테이블에 인덱스를 더 추가하십시오.
    • 다른 것?

  • 인 20,000 행 30 초 걸리는 MVC 동작 (매개 변수가있는 jqGrid, sidx = 정렬 열 및 sord = 정렬 순서에 의해 공급된다)

    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 토륨 수 -

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

    내가 대신 조건의 문자열에 전달할 수 있도록 .OrderBy() 절은 LinqExtensions를 사용하는이 : .GetPaged()이가하는 genericRepository.GetPaged을 (호출 ProductRepository.GetPaged)를 호출 그것을 느리게하고 있습니까?

    그리고 마지막으로 ListPage 편리 페이징에 대한 요구에있는 jqGrid 속성 마무리를위한 단지 클래스 :

    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는 다음과 같습니다

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

    .OrderBy 방법은 다음 두 가지 방법으로 구성 관습은 :

    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

    편집하면 genericBased 코드로 돌아갈 때 OrderBy가 비 generic 코드를 사용할 때 매우 혼란 스럽습니다 ... 명확하게 할 수 있습니까? 나는 명백한 것을 놓치고 있는가? –

    +0

    죄송합니다. 당신이 무엇을 요구하는지 모르겠습니다 -이'OrderBy()'는 다른 클래스에 정의 된 확장 메소드입니다. –

    +0

    글쎄,'GetQuery()'는'IQueryable '(generic)을 반환 할 것입니다; 'GetQuery(). 당신이 보여줄 방법을 사용하는 OrderBy (sidx + ""+ sord)'는'IQueryable' (non-generic)이 될 것이다. AFAIK는 비 제네릭에 대해 정의 된 * Skip (...) 등이 없습니다 ... 어떻게 작동 할 것인지 확실하지 않습니까? –

    답변

    6

    나를 괴롭히는 비트는 다음과 같습니다.

    .Take(rows).AsQueryable() 
    
    당신이 AsQueryable()를 추가 할 필요가 있다는 사실은 당신이 쿼리의 잘못된 끝에 페이징을 수행 할 수있는 의미, 현재 IEnumerable<T> 것을 나에게 제안 (네트워크를 통해 다시 방법 너무 많은 데이터를 가져 오는). GetQuery()과 사용자 정의 OrderBy()이 없으면 확실하지 않습니다.하지만 항상 그렇듯이 먼저 추적을 통해 쿼리를 프로파일 링해야합니다. 어떤 쿼리가 실행되고 어떤 데이터가 반환되는지 확인하십시오. EFProf을 사용하면 쉽게 만들 수 있지만 SQL 추적이면 충분합니다.

    +1

    +1 - 또한 약간 알려진'ObjectQuery 'ext meth가'.ToTraceString()'으로 불린다. 실행될 SQL 쿼리를 보여줍니다. 로깅에 매우 편리합니다. – RPM1984

    +0

    미안 해요,'GetQuery()'는 하나의 라이너입니다 :'return ObjectSet.AsQueryable();'. OrderBy()에 대한 코드를 편집하고 추가 할 것입니다 - 어디서 왔는지는 모르겠습니다. linqextensions.codeplex.com/ –

    +0

    @JK - 솔직히 말해서, 코드는'.AsQueryable()'을 제거하면 작동합니다. –

    관련 문제