ROW_NUMBER 没有 ORDER BY

问题描述 投票:0回答:4

我必须在现有查询中添加行号,以便我可以跟踪已添加到 Redis 中的数据量。如果我的查询失败,那么我可以从其他表中更新的该行开始。

查询从表中 1000 行后开始获取数据

SELECT * FROM (SELECT *, ROW_NUMBER() OVER (Order by (select 1)) as rn ) as X where rn > 1000

查询工作正常。如果有什么方法可以让我在不使用 order by 的情况下获得行号。

这里的

select 1
是什么?

查询是否经过优化,或者我可以通过其他方式来完成。请提供更好的解决方案。

sql sql-server t-sql window-functions
4个回答
156
投票

无需担心在

ORDER BY
表达式中指定常量。以下内容摘自Itzik Ben-Gan撰写的
Microsoft SQL Server 2012 High-Performance T-SQL Using Window Functions
(可从Microsoft免费电子书网站免费下载):

如前所述,窗口顺序子句是强制性的,并且 SQL Server 不允许基于常量进行排序,例如, 按 NULL 排序。但令人惊讶的是,当传递基于 返回常量的子查询 — 例如,ORDER BY (SELECT NULL)—SQL Server 将接受它。同时,优化器 取消嵌套或扩展表达式并意识到排序是 所有行都相同。因此,它消除了订购要求 从输入数据。这是一个完整的查询来证明这一点 技术:

SELECT actid, tranid, val,
 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
FROM dbo.Transactions;

在 Index Scan 迭代器的属性中观察 Ordered 属性为 False,意味着迭代器不需要返回 按索引键顺序排列的数据


上面的意思是,当您使用常量排序时,不会执行。我强烈建议阅读这本书,因为

Itzik Ben-Gan
深入描述了窗口函数如何工作以及如何在使用它们时优化各种情况。


18
投票

您可以使用任何文字值,例如:

order by (select 0)

order by (select null)

order by (select 'test')

16
投票

尝试

order by 1
。阅读错误消息。然后恢复
order by (select 1)
。请意识到,无论是谁编写此代码,都曾在某个时候阅读过错误消息,然后决定正确的做法是欺骗系统不引发错误,而不是意识到错误试图提醒他们注意的基本事实。

表格没有固有的顺序。如果您想要某种可以依赖的排序形式,则需要为任何

ORDER BY
子句提供足够的确定性表达式,以便每一行都被唯一标识和排序。

任何其他事情,包括欺骗系统不发出错误,都是希望系统会做一些明智的事情,而不使用提供给您的工具来确保它做一些明智的事情 - 一个明确指定的

ORDER BY
子句。


6
投票

这里的 select 1 是什么?

在这种情况下,查询的作者实际上并没有考虑任何特定的排序。

ROW_NUMBER
需要
ORDER BY clause
,因此提供它是满足解析器的一种方式。

按“常量”排序将创建“不确定”顺序(查询优化器能够选择它认为合适的任何顺序)。

最简单的思考方式是:

ROW_NUMBER() OVER(ORDER BY 1)    -- error
ROW_NUMBER() OVER(ORDER BY NULL) -- error

提供常量表达式来“欺骗”查询优化器的可能场景很少:

ROW_NUMBER() OVER(ORDER BY (SELECT 1)) -- already presented

其他选项:

ROW_NUMBER() OVER(ORDER BY 1/0)       -- should not be used
ROW_NUMBER() OVER(ORDER BY @@SPID)
ROW_NUMBER() OVER(ORDER BY DB_ID())
ROW_NUMBER() OVER(ORDER BY USER_ID())

db<>小提琴演示

© www.soinside.com 2019 - 2024. All rights reserved.