C# Entity Framework + Linq - 如何加速慢速查询?

标签 c# linq performance asp.net-mvc-2 jqgrid

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

现在我正在尝试执行完全相同的查询,其中表有 20,000 行 - 查询需要 30 秒。我怎样才能进一步改进它? 2 万行仍然不是一个很大的数字。

我有一些可能的想法是:

  • 可以通过去规范化去除连接和求和来改进
  • 创建一个 View 并查询,而不是查询和连接表
  • 不要查询整个表,让用户先选择一些过滤器(例如 A | B | C .. 等过滤器)
  • 为表添加更多索引
  • 还有别的吗?

这是 2 万行需要 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.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();
}

自定义 .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);
}

最佳答案

让我担心的一点是:

.Take(rows).AsQueryable()

您需要添加 AsQueryable() 的事实向我建议它目前是IEnumerable<T> ,这意味着您可能在查询的错误端执行分页(通过网络返回方式太多数据)。没有GetQuery()和习俗 OrderBy()很难确定 - 但一如既往,要做的第一件事是通过跟踪分析查询。查看执行了什么查询以及返回了什么数据。 EFProf可能会使这变得容易,但 SQL 跟踪可能就足够了。

关于C# Entity Framework + Linq - 如何加速慢速查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4231011/

相关文章:

javascript - jQuery.grep 与 Array.filter 的性能对比

java - 使用 Boolean.valueOf() 方法 vs(或 Java 1.5 自动装箱)创建 boolean 对象

python - numpy argsort 性能缓慢

c# - 发送或接收数据的请求被拒绝,因为套接字未连接。 .

c# - 如何将 Visual Studio 默认为 C# 项目而不是 VB.NET?

c# - 通过检查元素的条件将列表拆分为子列表

LINQ to SQL DAL + BLL + 演示文稿

c# - 是什么导致 Unity 内存泄漏?

c# - 获取数组中的枚举元素

c# - 如何在 C# 中进行完全外部连接?