LINQ排序1000000记录的最佳方法是什么

时间:2016-03-13 22:00:02

标签: c# entity-framework linq sorting

我想用Linq对1,000,000条记录进行排序和分页。我不知道我用来获取数据的方式或是否正确,因为网页速度太慢。

这是我的代码:

public HttpResponseMessage GetAllProducts(int page, string SortColumn,string Name = null)
{
    const int PageSize = 4;
    HttpResponseMessage response = null;
    IEnumerable<Product> result = null;

    if (string.IsNullOrEmpty(Name))
    {
        result = db.Products.OrderBy(SortColumn).AsEnumerable();

    }
    else
    {
        result = db.Products
            .Where(p => p.Name.StartsWith(Name))
            .OrderBy(SortColumn).AsEnumerable();
    }


    int NumberOfPages = result.Count();
    var begin = (page - 1) * PageSize;
    var data = result.Skip(begin).Take(PageSize).AsEnumerable();


    ProductPager myproduct = new ProductPager
    {
        ProductList = data,
        TotalRecords = NumberOfPages

    };
    response = Request.CreateResponse(HttpStatusCode.OK, myproduct);
    return response;


}

1 个答案:

答案 0 :(得分:8)

您目前正在将所有100万条记录从数据库中提取到内存中,并将Skip()Take()应用于该集合。这非常昂贵。将您的IEnumerable<Product>更改为IQueryable<Product>并删除对.AsEnumerable()的调用。

这就是我要做的事情:

public HttpResponseMessage GetAllProducts(int page, string sortColumn, string name = null)
{
    const int PageSize = 4;
    IQueryable<Product> query = db.Products;

    if (!string.IsNullOrEmpty(Name))
    {
        query = query.Where(p => p.Name.StartsWith(name));
    }

    int numberOfRecords = result.Count();
    var begin = (page - 1) * PageSize;
    var data = query.OrderBy(sortColumn)
        .Skip(begin).Take(PageSize)
        .ToList();

    ProductPager myproduct = new ProductPager
    {
        ProductList = data,
        TotalRecords = numberOfRecords 
    };
    return Request.CreateResponse(HttpStatusCode.OK, myproduct);
}

发生了什么事?

实体框架是 LINQ查询提供程序。当您访问db.Products时,会返回一个实现IQueryable<Product>IEnumerable<Product>的对象。这为您提供了两组LINQ扩展方法,其中许多方法相互重叠(例如Where()Skip()Take()OrderBy()Count())。

调用与IQueryable<>相关的方法,将执行以下两项操作之一:

  1. 对于不需要立即评估的操作(如Where()OrderBy()),没有与数据库相关的实际工作:您只需要另一个IQueryable<>来记录事实上,您想要使用特定参数调用特定的LINQ方法。
  2. 对于需要立即评估的操作(如Count()),将发出一个SQL查询,表示您到目前为止已构建的查询,并且您将检索所需的结果。例如,SQL Server实际上会计算必要的记录,只返回一个数字,而不是返回单个记录。
  3. 另一方面,如果调用与IEnumerable<>相关的方法,则会生成一个对象(将立即或稍后评估)执行原始查询(为数据库中的所有产品提供)和然后迭代它来做一些事情,比如过滤,跳过,接受,排序和计数。

    由于IQueryable<> 更具体而不是IEnumerable<>,因此通常会调用IQueryable<>扩展方法,除非您不遗余力地将结果转换为IEnumerable<>(这是您在代码中所做的)。