Sql 最好的分页方式

Sql best way to pagination

我有#temp table,我需要对 table 中的所有数据进行分页。 table 分页的最佳方法是什么?

create table #temp (
    Id int
    ,SomeName nvarchar(100)
)

create table #tempPage (
    Id int
    ,SomeName nvarchar(100)
    ,PageIndex int
)
--Test data
insert #temp (Id, SomeName) values
(1,'A'),
(2,'B'),
(3,'C'),
(4,'D'),
(5,'F'),
(6,'G'),
(7,'H'),
(8,'A1'),
(9,'B1'),
(10,'C1'),
(11,'D1'),
(12,'F1'),
(13,'G1'),
(14,'H1');

--Page size
declare @PageSize int = 5

--Max page count
declare @MaxPages float = (
    select
        case when count(Id)%@PageSize>0 then count(Id)/@PageSize+1 else count(Id)/@PageSize end
    from #temp
)

declare @PageFrom int = 0

declare @CurrentPage int = 1

while @CurrentPage <= @MaxPages
begin
    insert #tempPage (Id, SomeName, PageIndex)
    SELECT
        Id, SomeName, @CurrentPage
    FROM #temp
    ORDER BY id OFFSET @PageFrom ROWS
    FETCH NEXT @PageSize ROWS ONLY;
    set @PageFrom = @PageFrom + @PageSize
    set @CurrentPage = @CurrentPage + 1

end

select * from #tempPage

drop table #temp
drop table #tempPage

结果:

大数据处理速度很慢。我用的是Sql 2012

女士

基于集合的操作性能更好。避免逐行处理。

我们可以使用数据库分配的row_number除以每页我们想要的记录数来生成页面索引。如果我们截断/(四舍五入并消除小数点),我们将获得所需的页面索引。

类似于:

SELECT ID
    , SomeName
    , round(ROW_NUMBER() OVER(ORDER BY SomeName ASC)/5,0,1) AS PageIndex
FROM #temp
ORDER BY PageIndex, SomeName
  • 5 表示每“页”的记录数
  • 0 因为我们不关心小数,但我们不希望在截断小数之前发生舍入。
  • 1 截断为 0 位小数 w/o 四舍五入。

我假设您知道可以将其包装在 CTE 中并添加一个 where 子句以获得所需的特定页面

由于您正在寻找最佳的分页方法,并且您正确地说您的解决方案对于大量数据来说速度很慢,因此您必须根据用户请求一次获取一页数据。

当用户点击第 2 页时,您将获得第 2 页的记录,而不是全部。

这里是示例代码

declare @PageNumber int = 2; -- just an example, will come from parameter
declare @PageTo int = @PageSize * @PageNumber;
declare @PageFrom int = @PageTo - @PageSize;

    SELECT
        Id, SomeName, @PageNumber
    FROM #temp
    WHERE Id > @PageFrom AND Id <= @PageTo

drop table #temp

您可以使用 OFFSET & FETCH NEXT 功能, OFFSET 关键字只从 row_number 带来,而 FETCH NEXT 带来直到。 例如:

 USE AdventureWorks2008R2
    GO
    SELECT 
      BusinessEntityID
      ,PersonType
     ,FirstName + ' ' + MiddleName + ' ' + LastName 
    FROM Person.Person
     ORDER BY BusinessEntityID ASC
      OFFSET 100 ROWS 
      FETCH NEXT 5 ROWS ONLY
    GO

这样就可以利用参数进行分页,例如:

SELECT
  BusinessEntityID
 ,PersonType
 ,FirstName + ' ' + MiddleName + ' ' + LastName 
FROM Person.Person
 ORDER BY BusinessEntityID
  OFFSET (@PageNo - 1) * @RowCountPerPage ROWS
  FETCH NEXT @RowCountPerPage ROWS ONLY
GO 

为了更深入的理解和性能,您可以阅读this - Pagination with OFFSET / FETCH : A better way文章