【问题标题】:Sql Server paging rows by offset - without 'ORDER BY'Sql Server 按偏移量分页行 - 没有'ORDER BY'
【发布时间】:2023-03-28 03:25:01
【问题描述】:

我的生产表包含超过一百万条记录。要求分页查询通过 OFFSET 和 LIMIT 参数检索记录(类似于 MySql 的 LIMIT 子句),而不对结果集进行排序,就像行的自然顺序在表扫描中一样,因为“ORDER BY”会产生不可接受的性能影响,包括传统技术 ROW_NUMBER() OVER (ORDER BY ...) 中使用的“ORDER BY”子句。
有哪位专家可以提供解决这个问题的方法吗?对结果集没有任何排序的分页记录。 例如

Create table RandomRecords(int id, datetime recordDate)
----
select * from RandomRecords
34, '1/1/2009'
123, '8/1/2008'
11, '2/23/2008'
10, '3/2/2008'
4, '2/5/2009'
78, '1/1/2008'
55, '5/2/2008'
6666, '2/12/2009'
....
one million rows

-----
paging query with @Offset = 3 and @limit=4 generates
11, '2/23/2008'
10, '3/2/2008'
4, '2/5/2009'
78, '1/1/2008'

【问题讨论】:

  • 你能对你的表结构做更多解释吗?似乎您的 RandomRecords 表是您的情况的过于简单化的示例。

标签: sql sql-server paging


【解决方案1】:

这只是对 Remus 回答的补充。

分页主键不会导致 SQL Server 排序,因为主键是按排序顺序存储的。您可以在没有 WITH 语句的情况下对主键进行分页,例如:

SELECT *
FROM (
    SELECT 
        ROW_NUMBER() OVER (ORDER BY PrimaryKey) as rn
    ,   *
    FROM BigTable
) sub 
WHERE sub.rn BETWEEN 3 and 7

子查询仍然是必需的,因为您不能在 WHERE 语句中使用 ROW_NUMBER()。

【讨论】:

    【解决方案2】:

    ORDER BY 只有在无法通过索引解决时才会产生额外的影响。如果您看到“不可接受”的影响,则意味着您没有正确设计您的表,或者您没有正确设计查询。

    一些我们不变的 ORDER BY 表达式SELECT ..., ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM ...。但如果设计不当,仍可能会产生分拣线轴。

    考虑一下你的例子:

    CREATE TABLE RandomRecords (recordId int not null primary key, id int);
    INSERT INTO RandomRecords (id) values (...)
    WITH PagedRandomRecords (
       SELECT id, 
          ROW_NUMBER() OVER (ORDER BY recordId) as rn
          FROM RandomRecords)
    SELECT id FROM PagedRandomRecords
       WHERE rn BETWEEN 3 and 7;
    

    这将对数据进行排序,因为 recordId PK 聚集索引可以按所需顺序传递行。

    【讨论】:

    • ‒1 你是谁来确定什么是“不可接受的影响”
    【解决方案3】:

    如果您仍然找不到 ORDER BY 的列,您可以按添加的常量列进行排序,以使查询正常工作:

    SELECT col1, col2 FROM
       (SELECT col1, col2,
          ROW_NUMBER() OVER (ORDER BY alias_sort) AS alias_rownum
       FROM 
          (SELECT col1, col2, 0 AS alias_sort
          FROM 
             (SELECT col1, col2
             FROM ...)))
    WHERE alias_rownum >= 12345 AND alias_rownum <= 67890
    

    "0 AS alias_sort" 提供在父查询的 ORDER BY 子句中使用的常量列。顶部外部查询提供了过滤器并去掉了代理 alias_rownum 和 alias_sort 内部列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-24
      • 2010-09-16
      相关资源
      最近更新 更多