【问题标题】:Default row ordering for select query in oracleoracle中选择查询的默认行排序
【发布时间】:2010-10-28 07:45:29
【问题描述】:

在 Oracle 中,如果未指定“order by”子句,则选择查询的默认行顺序是什么。

是吗

  1. 插入行的顺序
  2. 根本没有默认排序
  3. 以上都不是。

【问题讨论】:

  • 这个问题被问了很多(我已经看到它在几个论坛中弹出)。我认为这可能是由于错误地认为“ORDER BY”将迫使 CBO 执行排序,这显然比执行无序查询更昂贵。有一些方法可以提高 Oracle 中的排序性能,但它们不需要避免“ORDER BY”子句。
  • 已经有足够的答案来说明这一点,但只是补充一下 - 没有明确的顺序,运行时引擎将在从存储中获取行时返回行。它如何获取行取决于执行计划。执行计划可能会发生变化,尤其是从 11g 开始,它具有诸如统计反馈等自适应特性。行存储在不保证顺序的块中。

标签: oracle sql-order-by


【解决方案1】:

根据 Tom Kyte:“除非并且直到您将“order by”添加到查询中,否则您不能对返回的行的顺序说任何话。好吧,除了“您不能依赖于返回的行的顺序” '。”

请参阅 asktom.com 上的 this question

对于 ROWNUM,它实际上并不存在,因此不能“释放”。 ROWNUM 是在从表中检索到记录后分配的,这就是为什么“WHERE ROWNUM = 5”总是无法选择任何记录的原因。

@ammoQ:您可能想阅读this AskTom article 的 GROUP BY 排序。简而言之:

Query 中的 Group By 子句是否保证输出数据将是 按 Group By 列排序 订购,即使没有订购方式 条款?

我们说...

绝对不是,

从来没有,从来没有,从来没有 会的。

【讨论】:

  • 谢谢,我知道那篇文章。 2 年前,我非常仔细地研究了它,在花了数周时间思考这个问题之后:为什么这个程序在 10g 上表现不同?
  • 简单地说,因为 Oracle 在 10g 中做了一些不同的事情。但是,这不是 Oracle 中的错误! Oracle NEVER siad GROUP BY 会对结果进行排序,Tom 展示了它在 9i 中是如何失败的。仅仅因为它经常看起来是这样就意味着人们依赖它。那篇文章除了内容丰富之外,还是人们无法或不愿意接受一个简单概念的最令人惊奇的例证之一,因为它与他们自己的轶事观察不同。这也很有趣。如果您希望对数据进行排序,请使用 ORDER BY。
  • @DCookie 这种行为是仅限于 Oracle 还是适用于 MySQL、Postgres 等所有关系型数据库?
  • @NarendraJaggi:这适用于所有关系数据库。
  • 8 年,它仍然有助于回答为什么会发生某些错误。感谢分享文章!
【解决方案2】:

没有明确的默认排序。出于显而易见的原因,如果您创建一个新表,插入几行并执行没有“where”子句的“select *”,它将(很可能)按照插入的顺序返回这些行。

但您永远不应该依赖默认订单的发生。如果您需要特定的订单,请使用“order by”子句。例如,在最高 9i 的 Oracle 版本中,执行“分组依据”也会导致行按组表达式排序。在 10g 中,这种行为不再存在!因此,升级 Oracle 安装给我带来了一些工作。

【讨论】:

  • 答案是肯定的,但要挑剔:实际上并不是那么“明显” - 不能保证新行会以任何特定的顺序插入到新表中,也不能保证 SELECT 没有ORDER BY 必然会按照创建顺序访问表中的所有块。
  • 是的,没有任何保证。但我很难创建一个不能这样工作的场景。
  • 如果您创建一个包含 100 条记录的表,删除前 50 条然后插入另外 10 条,Oracle 将倾向于重新使用已删除行中的空间(受大量 ifs、buts 等影响) .因此,即使 Oracle 以相同的顺序访问块,最后插入的 10 条记录在没有 ORDER BY 的查询中往往会排在第一位
  • 很明显。这就是为什么他的例子是if you create a **new** table, insert a few rows and do a select 虽然我会说...it will _most likely_ return...
【解决方案3】:

已经说过,当您没有指定 ORDER BY 子句时,Oracle 可以按照它想要的任何顺序为您提供行。当您不指定 ORDER BY 子句时,推测订单将是什么是没有意义的。在你的代码中依赖它,是一个“限制职业的举动”。

一个简单的例子:

SQL> create table t as select level id from dual connect by level <= 10
  2  /

Tabel is aangemaakt.

SQL> select id from t
  2  /

        ID
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10

10 rijen zijn geselecteerd.

SQL> delete t where id = 6
  2  /

1 rij is verwijderd.

SQL> insert into t values (6)
  2  /

1 rij is aangemaakt.

SQL> select id from t
  2  /

        ID
----------
         1
         2
         3
         4
         5
         7
         8
         9
        10
         6

10 rijen zijn geselecteerd.

这只是在简单的删除+插入之后。还有许多其他可以想象的情况。并行执行、分区、索引组织表等等。

底线,正如 ammoQ 所说的那样:如果您需要对行进行排序,请使用 ORDER BY 子句。

【讨论】:

  • +1 表示依赖于无序查询排序的“职业限制移动”。
  • 感谢您的链接。确实,我就是从那里得到这句话的。
  • 如果我不删除或插入怎么办?我从头开始重新创建一个表select * from another_table order by filed1
【解决方案4】:

除非您指定order by,否则您绝对不能依赖任何排序。特别是对于 Oracle,我实际上已经看到完全相同的查询(没有连接),在几秒钟内彼此运行两次,在一个临时没有更改的表上,返回一个完全不同的顺序。当结果集很大时,这似乎更有可能。

Rob van Wijk 提到的并行执行可能解释了这一点。另请参阅 Oracle 的 Using Parallel Execution 文档。

【讨论】:

    【解决方案5】:

    受索引影响, 如果有索引,它将返回一个升序, 如果没有任何索引,则返回插入的订单。

    【讨论】:

      【解决方案6】:

      您可以使用 CREATE TABLE 语句的 ORGANIZATION 子句通过 INSERT 修改数据存储到表中的顺序

      【讨论】:

      • 嗯不是真的。 ORGANIZATION 对堆表没有任何作用(这是默认设置)。它仅适用于具有特定用途的 organization indexedexternal 表。 Find out more
      【解决方案7】:

      虽然它应该是 rownnum(你的 #2),但它确实不能保证,你不应该 100% 相信它。

      【讨论】:

      • rownum 报告行返回的顺序;它不能帮助您确定它们应该返回的顺序。
      【解决方案8】:

      我相信它使用了 Oracle 的隐藏 Rownum 属性。

      所以你的 #1 可能是正确的假设没有删除可能已经释放 rownums 供以后使用。

      编辑:正如其他人所说,你真的不应该依赖这个,永远。除了删除之外,还有许多不同的条件会影响默认排序行为。

      【讨论】:

      • ROWNUM 不是属性,而是仅在查询时分配。 ROWID 也不是一个属性——它只是将文件、块和行表示为单个值。它确实作为指向实际行的指针存储在索引中。
      猜你喜欢
      • 1970-01-01
      • 2016-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多