Sql Server按偏移分页行 - 没有'ORDER BY'

时间:2009-10-31 15:28:40

标签: sql sql-server paging

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

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'

3 个答案:

答案 0 :(得分:3)

除了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()。

答案 1 :(得分: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聚集索引可以按所需顺序传递行。

答案 2 :(得分:0)

如果仍然没有找到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

&#34; 0 AS alias_sort &#34;提供父查询中ORDER BY子句中使用的常量列。顶部外部查询提供过滤器并删除代理alias_rownum和alias_sort内部列。

相关问题