111

所以,我有一个函数可以返回一些我想在我的网站上实现分页的记录。有人建议我使用 SQL Server 2012 中的 Offset/Fetch Next 来完成此操作。在我们的网站上,我们有一个区域列出了记录总数以及您当时所在的页面。

之前,我获得了整个记录集,并且能够以编程方式在其上构建分页。但是使用带有 FETCH NEXT X ROWS ONLY 的 SQL 方式,我只返回 X 行,所以我不知道我的总记录集是多少以及如何计算我的最小和最大页面。我可以告诉这样做的唯一方法是调用该函数两次并在第一个上计算行数,然后使用 FETCH NEXT 运行第二个。有没有更好的方法不会让我运行两次查询?我正在努力提高性能,而不是减慢它。

4

4 回答 4

157

我在使用 COUNT( ) OVER() 方法时遇到了一些性能问题。(我不确定它是否是服务器,因为它需要 40 秒才能返回 10 条记录,然后后来没有任何问题。)这种技术在所有条件下都有效,而无需使用 COUNT( ) OVER() 并完成一样:

DECLARE 
    @PageSize INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, Name
    FROM Table
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)
SELECT *
FROM TempResult, TempCount
ORDER BY TempResult.Name
    OFFSET (@PageNum-1)*@PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY
于 2013-11-21T19:37:01.723 回答
129

您可以使用COUNT(*) OVER()... 这是一个使用的快速示例sys.all_objects

DECLARE 
  @PageSize INT = 10, 
  @PageNum  INT = 1;

SELECT 
  name, object_id, 
  overall_count = COUNT(*) OVER()
FROM sys.all_objects
ORDER BY name
  OFFSET (@PageNum-1)*@PageSize ROWS
  FETCH NEXT @PageSize ROWS ONLY;

但是,这应该保留给小数据集;在较大的集合上,性能可能很糟糕。请参阅此 Paul White 文章以获得更好的替代方案,包括维护索引视图(仅当结果未过滤或您WHERE提前知道子句时才有效)和使用ROW_NUMBER()技巧。

于 2012-09-18T03:42:56.300 回答
3

显然,根据查询的不同,结果可能会有很大差异。我用这些结果测试了我的案例:(8 个连接,2 个子查询,5800 行不同的结果,5900 行不不同):

*在我的情况下, Aaron Bertrand 的回答没有奏效,因为COUNT(1) OVER()似乎包括被过滤掉的行DISTINCT

使用临时表:

DECLARE 
  @PageSize INT = 10, 
  @PageNum  INT = 1;
 
SELECT
  name, object_id
INTO #MY_TEMP
FROM sys.all_objects

SELECT *
FROM #MY_TEMP
ORDER BY name
  OFFSET (@PageNum-1)*@PageSize ROWS
  FETCH NEXT @PageSize ROWS ONLY;

SELECT COUNT(1) FROM #MY_TEMP
-- or
-- SELECT @MY_OUTPUT_PARAM = COUNT(1) FROM #MY_TEMP

DROP TABLE #MY_TEMP

临时表的好处是计数可以分成不同的结果或输出参数。

于 2021-03-29T16:01:45.217 回答
1

基于詹姆斯莫伯格的回答

Row_Number()如果您没有 SQL Server 2012 并且不能使用 OFFSET,这是使用的替代方法

DECLARE 
    @PageNumEnd INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, NAME
    FROM Tabla
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)

select * 
from
(
    SELECT
     ROW_NUMBER() OVER ( ORDER BY PolizaId DESC) AS 'NumeroRenglon', 
     MaxRows, 
     ID,
     Name
    FROM TempResult, TempCount

)resultados
WHERE   NumeroRenglon >= @PageNum
    AND NumeroRenglon <= @PageNumEnd
ORDER BY NumeroRenglon
于 2016-04-27T23:11:22.857 回答