Pagination 如何使用对数据库的1次调用实现LINQ2实体的自定义分页

Pagination 如何使用对数据库的1次调用实现LINQ2实体的自定义分页,pagination,linq-to-entities,entity-framework-5,Pagination,Linq To Entities,Entity Framework 5,我正在从事ASP.NET Web表单项目,我使用jquery datatable可视化从SQL服务器获取的数据。我需要传递当前页面的结果以及到目前为止我拥有以下代码的结果总数: var queryResult = query.Select(p => new[] { p.Id.ToString(), p.Name,

我正在从事
ASP.NET Web表单
项目,我使用
jquery datatable
可视化从
SQL
服务器获取的数据。我需要传递当前页面的结果以及到目前为止我拥有以下代码的结果总数:

var queryResult = query.Select(p => new[] { p.Id.ToString(), 
                                            p.Name, 
                                            p.Weight.ToString(),
                                            p.Address })
                                            .Skip(iDisplayStart)
                                            .Take(iDisplayLength).ToArray();
当我将结果返回到视图时得到的结果如下:

iTotalRecords = queryResult.Count(),
是用户选择每页查看的记录数。合乎逻辑,但在构建方法链接时我没有考虑它。现在我在考虑实现这一点的最佳方式。由于它可能用于相对较大的数据量(10000行,可能更多),我希望将尽可能多的工作留给
SQL
服务器。然而,我发现了一些关于这方面的问题,我得到的印象是,我必须对数据库进行两次查询,或者在我的代码中操纵整个结果。但我认为,当你必须处理许多记录时,这将是无效的


那么,我可以在这里做些什么来获得最佳性能呢?

关于您想要的产品,我认为没有一个简单的答案

我相信目前唯一可以做到这一点的方法是运行多个查询,就像您已经建议的那样,无论这是封装在存储过程(SPROC)调用中还是由EF生成

但是,我相信您可以进行优化,使查询运行得更快

首先,在将方法链接在一起时,每次执行查询都可能导致重新生成查询,这意味着执行的实际查询需要在执行之前由SQL Server重新编译和缓存(如果这是您选择的技术)。这通常只需要几毫秒,但是如果正在执行的查询只需要几毫秒,那么这是相对昂贵的

实体框架将转换此Linq查询并使用派生表执行它。有了一个大约1k条记录的小结果集,您当前的解决方案可能最适合分页。这还取决于方法链接生成的SQL过滤有多复杂

如果要分页的结果集增长到15k,我建议编写一个存储过程以获得最佳性能和可伸缩性,将记录插入临时表并对其运行两个查询,首先获取分页记录,然后获取总结果

alter proc dbo.usp_GetPagedResults
    @Skip int = 10,
    @Take int = 10
as
begin

    select
        row_number() over (order by id) [RowNumber],
        t.Name,
        t.Weight,
        t.Address
    into
        #results
    from
        dbo.MyTable t

    declare @To int = @Skip+@Take-1
    select * from #results where RowNumber between @Skip and @To
    select max(RowNumber) from #results

end
go
您可以使用EF将存储过程调用映射到实体类型,或创建包含结果和结果数的新自定义类型。

我发现运行上述存储过程的成本大约是运行查询的三分之一,EF根据15k记录的结果集大小生成查询以获得相同的结果。但是,如果由于临时表的创建而只创建了1K记录结果集,那么它比EF查询慢三倍

将此逻辑封装在存储过程中,可以在结果集增长时重构和优化查询,而无需更改任何基于应用程序的代码


建议的解决方案不使用存储过程中实体框架创建的派生表查询,因为我发现直接运行存储过程和查询之间的性能差别很小。

回答得很好。谢谢分享你的知识!