【问题标题】:ROW_NUMBER Without ORDER BYROW_NUMBER 无 ORDER BY
【发布时间】:2017-10-21 16:30:32
【问题描述】:

我必须在现有查询中添加行号,以便我可以跟踪已将多少数据添加到 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 tsql window-functions


    【解决方案1】:

    试试order by 1。阅读错误信息。然后恢复order by (select 1)。意识到写这篇文章的人在某个时候已经阅读了错误消息,然后决定正确的做法是欺骗系统不引发错误,而不是意识到错误试图提醒他们注意的基本事实。

    表格没有固有的顺序。如果您需要某种可以依赖的排序形式,您可以为任何 ORDER BY 子句提供足够的确定性表达式,以便每一行都被唯一标识和排序。

    其他任何事情,包括诱使系统不发出错误,都是希望系统会在不使用提供给您的工具的情况下做一些明智的事情来确保它确实做到了一些明智的 - 一个明确指定的ORDER BY 子句。

    【讨论】:

    • 所以我做得对,选择 1.?我没有找到任何其他解决此问题的方法
    • 我部分不同意这样的说法,“表格没有内在顺序。”我发现(从表格中选择时)它将使用集群返回其记录-索引顺序每次。现在开始加入表并进行更复杂的查询,然后我认为默认顺序可能取决于查询优化器采用的任何路线。顺便说一句:发问者不是询问是否将订购条款放在一起。您仍然可以拥有一个,她只是想知道是否可以在 Row_Number() 表达式中未指定它,它可以:ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    • @MikeTeeVee - 这个话题已经完蛋了。没有固有的用户可观察顺序。 通常从单个表中选择将遵循聚集索引顺序,但 SQL Server 不提供保证这种情况。但是,即使在这种情况下,您也可能会以轮播扫描结束——您的查询依赖于另一个已经开始表扫描的查询。您的查询开始从表的中间获取结果,因为那是扫描的位置,然后将开始第二次扫描以完成。即使只定义了聚集索引,也会出现乱序结果。
    • 哇,我不知道。感谢您提供信息丰富的回复!这么多年过去了,我又觉得自己像个新手了。
    【解决方案2】:

    你可以使用任何文字值

    order by (select 0)
    
    order by (select null)
    
    order by (select 'test')
    

    更多信息请参考这里 https://exploresql.com/2017/03/31/row_number-function-with-no-specific-order/

    【讨论】:

    • gotqn 在评论中说 select 1 表示随机顺序。因此,如果在查询中添加条件,其中行号> 1000。所以它可能会给出以前的记录,因为它给出的是随机顺序。或者正确使用
    • 每次执行查询时select 0都会给出相同的顺序?
    • @lucy - 也许有时会,但不能保证,因为那时没有订单。为保证相同的结果,请在 ORDER BY 子句中为每条记录使用一些唯一的数据。
    【解决方案3】:

    无需担心在ORDER BY 表达式中指定常量。以下引自Itzik Ben-Gan写的Microsoft SQL Server 2012 High-Performance T-SQL Using Window Functions(可从微软免费电子书网站免费下载):

    如前所述,窗口顺序子句是强制性的,而 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 深入描述了窗口函数的工作原理以及在使用它们时如何优化各种情况。

    【讨论】:

    • so query, SELECT * FROM (SELECT *, ROW_NUMBER() OVER (Order by (select NULL)) as rn) as X where rn > 1000 总是给出正确的结果。表示每次执行查询的顺序都相同
    • @lucy 不,每次执行查询的顺序都不会保持不变。使用(SELECT constant) 表示没有订单。您正在选择特定数量的数据 - 您可以执行 100 万次查询并返回相同的数据,但不能保证这一点。如果没有特定的排序,结果就不确定。
    【解决方案4】:

    这里的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<>fiddle demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-08
      • 2016-11-17
      • 2011-06-16
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      相关资源
      最近更新 更多