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

C#实体框架+Linq-如何加快慢速查询?

  •  6
  • JK.  · 技术社区  · 14 年前

    这个问题与 C# MVC2 Jqgrid - what is the correct way to do server side paging? 在那里,我询问并发现如何提高对2000行左右的表的查询性能。性能从10秒提高到1秒。

    现在,我正试图执行与表中有20000行完全相同的查询—查询需要30秒。如何进一步改进?两万排仍然不是一个巨大的数字。

    我有一些可能的想法是:

    • 可以通过取消规范化以删除连接和和来改进
    • 创建一个视图和查询,而不是查询和联接表
    • 不要查询整个表,让用户先选择一些过滤器(例如A | B | C。。etc过滤器)
    • 向表中添加更多索引
    • 还有别的吗?

    这是一个MVC操作,20000行需要30秒:(参数由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.GetPaged()调用ProductRepository.GetPaged,后者调用genericRepository.GetPaged(),从而执行以下操作:

    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,这样我就可以传入一个字符串而不是一个谓词-这是否会减慢它的速度?

    最后,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();
    }
    

    custom.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);
    }
    
    1 回复  |  直到 7 年前
        1
  •  6
  •   Marc Gravell    14 年前

    我担心的是:

    .Take(rows).AsQueryable()
    

    你需要补充的事实 AsQueryable() 告诉我现在 IEnumerable<T> ,这意味着您可能在查询的错误结尾执行分页(将 方式 网络上的数据太多)。没有 GetQuery() 还有习俗 OrderBy() 很难确定——但和往常一样,首先要做的是通过跟踪分析查询。查看执行的查询和返回的数据。 EFProf 这可能很容易,但是SQL跟踪可能就足够了。