Vla*_*cea 13 mysql postgresql oracle order-by derived-tables
我在与 Lukas Eder的Twitter 对话中偶然发现了这个问题。
尽管正确的行为是在最外层查询上应用 ORDER BY 子句,因为在这里,我们没有在最外层查询中使用 DISTINCT、GROUP BY、JOIN 或任何其他 WHERE 子句,为什么 RDBMS 不只是通过传入的数据是按内部查询排序的吗?
SELECT *
FROM (
SELECT * FROM table ORDER BY time DESC
) AS t
Run Code Online (Sandbox Code Playgroud)
在 PostgreSQL 上运行此示例时,至少,您会为内部查询和此派生表示例获得相同的执行计划,以及相同的结果集。
因此,我假设 Planner 将简单地丢弃最外层的查询,因为它是多余的,或者只是通过内部表的结果。
有没有人认为情况可能并非如此?
Luk*_*der 20
大多数数据库都非常清楚ORDER BY子查询中的 an是:
TOP或补充OFFSET .. FETCH)OFFSET .. FETCH或补充LIMIT)子选择中的 ORDER BY 子句不会影响查询返回的行的顺序。如果在最外面的全查询中指定了 ORDER BY 子句,则它只会影响返回的行的顺序。
措辞非常明确,就像 PostgreSQL 一样:
如果未选择排序,则行将以未指定的顺序返回。这种情况下的实际顺序将取决于扫描和连接计划类型以及磁盘上的顺序,但不能依赖于。只有明确选择了排序步骤,才能保证特定的输出顺序。
从这个规范中可以看出,ORDER BY派生表中的子句产生的任何排序都只是偶然的,并且可能与您的预期排序相吻合(在您的琐碎示例中的大多数数据库中都是如此),但依赖于这个。
特别是,DB2 有一个鲜为人知的特性,称为ORDER BY ORDER OF <table-designator>,可以如下使用:
SELECT C1 FROM
(SELECT C1 FROM T1
UNION
SELECT C1 FROM T2
ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE
Run Code Online (Sandbox Code Playgroud)
在这种特殊情况下,派生表的排序可以在最外层的 SELECT 中显式重用
多年来,Oracle 一直OFFSET采用使用实现分页的做法,ROWNUM只有在对派生表进行排序后才能合理计算:
SELECT *
FROM (
SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
FROM (
SELECT * FROM table ORDER BY time DESC
) t
) t
WHERE rn BETWEEN 10 AND 20
Run Code Online (Sandbox Code Playgroud)
可以合理地预期,至少在ROWNUM查询中,未来的 Oracle 版本不会破坏这种行为,以免破坏几乎所有遗留的 Oracle SQL,这些 SQL 尚未迁移到更理想的可读的 SQL 标准OFFSET .. FETCH语法:
SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
Run Code Online (Sandbox Code Playgroud)
Dav*_*ett 12
是的。如果没有ORDER BY子句,输出顺序是未定义的,查询计划器完全在其权限范围内,假设您知道并理解这一点。
它可能会决定,因为外部查询没有指定顺序,所以它可以删除内部查询中的排序以避免排序操作,尤其是在没有聚集索引或根本没有索引来支持排序的情况下。如果不是现在,可能在未来的版本中做。
永远不要依赖未定义的行为。如果您需要特定的排序,请ORDER BY在适当的位置给出一个子句。
小智 6
这是未定义行为的问题 - 对你有用,对我有用,在 prod 中重新格式化 HDD ;)
我们可以退后一步说,从某种意义上说,您是对的 - 没有任何合理的 RDBMS 会重新排列内部选择中的行的世俗理由。但它不能保证——这意味着将来可能有一个原因,供应商可以自由地这样做。这意味着任何依赖于这种行为的代码都受供应商可以做出的更改的支配,他们没有义务公开,因为它不是 API POV 的重大更改。
| 归档时间: |
|
| 查看次数: |
3463 次 |
| 最近记录: |