SELECT * FROM TABLE(流水线函数):我可以确定结果中行的顺序吗?

Posted

技术标签:

【中文标题】SELECT * FROM TABLE(流水线函数):我可以确定结果中行的顺序吗?【英文标题】:SELECT * FROM TABLE(pipelined function): can I be sure of the order of the rows in the result? 【发布时间】:2013-05-23 11:41:17 【问题描述】:

在下面的例子中,我总是会得到“1, 2”,还是有可能得到“2, 1”?你能告诉我你在文档中的哪个地方看到了保证是否存在?

如果答案是肯定的,这意味着没有ORDER BYORDER SIBLINGS 有一种方法可以确保SELECT 语句中的结果集顺序。

CREATE TYPE temp_row IS OBJECT(x number);
/

CREATE TYPE temp_table IS TABLE OF temp_row;
/

CREATE FUNCTION temp_func
RETURN temp_table PIPELINED
IS
BEGIN
    PIPE ROW(temp_row(1));
    PIPE ROW(temp_row(2));
END;
/

SELECT * FROM table(temp_func());

谢谢。

【问题讨论】:

:是的,如果你颠倒了 PIPE ROW 的顺序,那么它会给你输出 2,1 否则 1,2 。如果你想要特定的顺序,然后在中添加一个 order by 子句您的选择查询。否则选择查询将根据 PIPE ROW 序列返回数据 【参考方案1】:

我认为文档中没有任何地方可以保证返回数据的顺序。

有一个 2003 年的旧 Tom Kyte thread(所以 可能 已经过时了)声明不建议依赖隐式顺序,原因与您不依赖在普通 SQL 中排序。

1st:是从表函数返回的行的顺序 SQL 语句与“管道”条目的顺序完全相同 进入内部集合(因此不需要 order by 子句)?

...

跟进 2003 年 5 月 18 日 - 世界标准时间上午 10 点:

1) 也许,也许不是,我不会指望它。你不应该数 在结果集中的行顺序上,没有 order by。如果 你加入或做一些更复杂的事情,然后简单地“选择 * from table( f(x) )",行很可能以其他顺序返回。

从经验上看——它们似乎在被传送时会回来。我不 相信有据可查。

事实上,NESTED TABLE 类型的集合被明确记录在案 没有能力维持秩序

为了安全起见,如果您希望查询结果有序,您应该像往常一样在查询中声明明确的 ORDER BY。

话虽如此,我已经使用了您的函数并运行了 1000 万次迭代,以检查隐式顺序是否被破坏;不是。

SQL> begin
  2    for i in 1 .. 10000000 loop
  3      for j in ( SELECT a.*, rownum as rnum FROM table(temp_func()) a ) loop
  4
  5         if j.x <> j.rnum then
  6            raise_application_error(-20000,'It broke');
  7         end if;
  8      end loop;
  9    end loop;
 10  end;
 11  /

PL/SQL procedure successfully completed.

【讨论】:

感谢您的回答,Tom Kyte 2003 年的回答非常有趣。【参考方案2】:

此过程逻辑的工作方式与基于表的查询不同。您不能依赖从表中选择的顺序的原因是,您不能依赖 RDBMS 将行标识为所需集合的一部分的顺序。这部分是因为执行计划发生了变化,部分是因为很少有情况可以预测表中行的物理顺序。

但是,您在这里选择的函数可以保证从函数发出行的顺序。在没有连接、聚合或其他任何东西的情况下(即直接“从表(函数)中选择...”),我可以肯定行顺序是确定性的。

除非有明确的 order-by,否则该建议不适用于涉及表的地方,因此,如果您从不使用 order-by 的查询中加载 pl/sql 集合,那么当然行的顺序在集合中是不确定的。

【讨论】:

【参考方案3】:

此时已接受答案中的 AskTom 链接已损坏,但我找到了 newer yet very similar question。在一些“对乒乓球的误解”之后,Connor McDonald 最终承认,在涉及并行性和引用光标的某些条件下,排序是稳定的,并且仅与当前版本相关。引用:

并行性是这里的(潜在)风险。 正如当前所代表的,一个流水线函数只有在将引用光标作为输入时才能并行运行。当然,不能保证将来不会改变。 因此,您可以基于 假设 运行,即在 当前 版本中,您将按顺序恢复行,但您永远不能 100% 相信现在和永远都是这种情况.

因此不保证未来的版本。

有问题的函数会通过这个标准,因此它应该提供稳定的排序。但是,我个人不会相信它。我的情况(当我发现这个问题时)更简单:从字面上指定的集合中选择 - select column_value from table(my_collection(5,3,7,2)) 无论如何我更喜欢数据和索引之间的显式配对。这不是那么难,也不会更长。

Oracle 应该向 Postgres 学习,unnest(array) with ordinality 解决了这种情况,这是一个清晰易懂、值得信赖且有据可查的特性。

【讨论】:

以上是关于SELECT * FROM TABLE(流水线函数):我可以确定结果中行的顺序吗?的主要内容,如果未能解决你的问题,请参考以下文章

Mysql DB select from table where field语句java

select * from table where something VS select column from table where something

SqlServer对select * from (select *from table) 支持

select into from 与insert into select from区别

Mysql select id from table1 and select count(id) from table2

相当于“SELECT * FROM (SELECT table_name FROM ...)”的东西?