【问题标题】:Microsoft SQL Server PagingMicrosoft SQL Server 分页
【发布时间】:2011-07-17 04:29:33
【问题描述】:

stackoverflow 上有很多 sql server 分页问题,​​其中很多都在谈论使用ROW_NUMBER() OVER (ORDER BY ...) AND CTE。一旦您进入数十万行并开始对非主键值添加排序并添加自定义 WHERE 子句,这些方法就会变得非常无效。我有一个数百万行的数据集,我试图通过自定义排序和过滤进行分页,但我的性能很差,即使在我排序和过滤的所有字段上都有索引。我什至在每个索引中都包含了我的 SELECT 列,但这几乎没有帮助,并且严重膨胀了我的数据库。

我注意到无论您点击什么排序标准或页码,stackoverflow 分页只需要大约 500 毫秒。任何人都知道如何在具有数百万行的 SQL Server 2008 中有效地进行分页工作?这包括尽可能高效地获取总行数。

我当前的查询与这个关于分页的 stackoverflow 问题具有完全相同的逻辑: Best paging solution using SQL Server 2005?

【问题讨论】:

  • 我认为 stackoverflow 使用 nosql db。也许是内存缓存。
  • 您可以发布查询;一般原则是个好人,但他在现实世界中有问题;)
  • 不要在您想要排序(或过滤)的每一列上添加索引,帮助?这对我来说似乎很明显,但我不知道你是否尝试过。
  • 我在所有列上都有索引。在超过最初的几千个分页之后,查询时间开始线性上升......
  • SO 也在使用 Lucene,所以我想这些查询没有到达 SQL 服务器。

标签: sql-server pagination


【解决方案1】:

有人知道如何在具有数百万行的 SQL Server 2008 中高效地进行分页吗?

如果您想要准确完美的分页,没有什么可以替代为每条记录建立索引键(位置行号)。但是,还有其他选择。

(1) 总页数(记录)

  • 假设变化率很小,您可以使用来自sysindexes.rows(几乎是瞬间)的近似值。
  • 您可以使用触发器来保持完全准确的第二个表行计数

(2) 分页

(a)
您可以在记录的任一侧显示接下来的五页内的页面跳转。这些需要在每侧最多扫描 {page size} x 5。如果您的基础查询适合快速按照排序顺序进行,那么这应该不会很慢。因此,给定一条记录 X,您可以使用(假设排序顺序为 a asc, b desc

select top(@pagesize) t.*
from tbl x
inner join tbl t on (t.a = x.a and t.b > x.b) OR
                    (t.a < a.x)
where x.id = @X
order by t.a asc, t.b desc

(即 X 之前的最后 {page size} 条记录)

要返回五页,请将其增加到 TOP(@pagesize*5),然后从该子查询进一步 TOP(@pagesize)。

缺点:此选项要求您不能直接跳转到特定位置,您的选项只有 FIRST(简单)、LAST(简单)、NEXT/PRIOR、

(b)
如果分页总是非常具体和可预测的,请维护一个不包含行号间隙的 INDEXED 视图或触发器更新表。如果表通常只在频谱的一端看到更新,而删除的空白很容易通过移动不多的记录来快速填补,这可能是一种选择。

这种方法为您提供行数(最后一行),还可以直接访问任何页面。

【讨论】:

  • 这个想法很好,谢谢,我会试试这些东西
  • 我最终做的是在结果总数较小(小于 100K)时使用我的 Lucene 索引进行分页。当它更高时,我使用 SQL Server。 Sql server 不擅长在大表中分页小结果集。 Lucene 擅长在庞大的数据集中对较小的结果集进行分页。
  • 不妨将其标记为正确,因为它与仅使用 SQL Server 所能获得的一样好。我上面提到的混合方法效果很好。
【解决方案2】:

试试这个,假设你有如下国家表:

DECLARE  @pageIndex INT=0;
DECLARE  @pageSize INT= 10;
DECLARE  @sortByColumn NVARCHAR(200)='Code';
DECLARE  @sortByDesc BIT=0;

;WITH tbl AS (
    SELECT COUNT(id) OVER() [RowTotal], c.Id, c.Code, c.Name
    FROM dbo.[Country] c
    ORDER BY 
       CASE WHEN @sortByColumn='Code' AND @sortByDesc=0 THEN c.Code END ASC,
       CASE WHEN @sortByColumn='Code' AND @sortByDesc<>0 THEN c.Code END DESC,
       CASE WHEN @sortByColumn='Name' AND @sortByDesc=0 THEN c.Name END ASC,
       CASE WHEN @sortByColumn='Name' AND @sortByDesc<>0 THEN c.Name END DESC,
       ,c.Name ASC  --DEFAULT SORTING ORDER
    OFFSET @PageIndex*@pageSize ROWS
    FETCH NEXT @pageSize ROWS ONLY
    ) SELECT (@PageIndex*@pageSize)+(ROW_NUMBER() OVER(ORDER BY Id))[RowNo],* from tbl;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-06
    • 2016-05-21
    • 2015-09-29
    • 1970-01-01
    • 2013-03-03
    • 2010-12-17
    • 2011-06-19
    • 1970-01-01
    相关资源
    最近更新 更多