下面是有问题的示例SQL;该SQL应该在任何Oracle DBMS上运行(我正在运行11.2.0.2.0)。
注意结果集中的UUID值是如何不同的(一个是898,另一个是899),尽管是从内联视图/with子句中构建的。再往下看,你可以看到DBMS_RANDOM.RANDOM()没有这个副作用。
SQL:
WITH data AS (SELECT SYS_GUID () uuid FROM DUAL)
SELECT uuid, uuid
FROM data
输出:
UUID UUID_1
F8FCA4B4D8982B55E0440000BEA88F11 F8FCA4B4D8992B55E0440000BEA88F11
DBMS_RANDOM结果是一样的。
SQL:
WITH data AS (SELECT DBMS_RANDOM.RANDOM() rand FROM DUAL)
SELECT rand, rand
FROM data
输出:
RAND RAND_1
92518726 92518726
更有趣的是,我可以通过包含对DBMS_RANDOM.RANDOM的调用来更改行为/稳定sys_guid:
WITH data AS (
SELECT SYS_GUID () uuid,
DBMS_RANDOM.random () rand
FROM DUAL)
SELECT uuid a,
uuid b,
rand c,
rand d
FROM data
稳定SYS_GUID的SQL Fiddle:http://sqlfiddle.com/#!4/d41d8/29409
显示了奇怪的SYS_GUID行为的SQL Fiddle:http://sqlfiddle.com/#!4/d41d8/29411
发布于 2014-05-14 22:52:12
您可能会看到差异的原因的documentation gives a reason (强调我的):
警告:
因为SQL是一种声明性语言,而不是命令性语言(或过程性语言),所以如果函数是用命令性语言PL/编写的,则无法知道由SQL语句调用的函数将运行-even的次数。如果您的应用程序要求某个函数执行一定的次数,则不要从SQL语句调用该函数。请改用光标。
例如,如果应用程序要求为每个选定行调用函数,则打开游标,从游标中选择行,然后为每行调用该函数。此技术可确保对函数的调用次数等于从游标中提取的行数。
基本上,Oracle不指定一个函数将在sql语句中被调用多少次:它可能取决于版本、环境、访问路径以及其他因素。
但是,有一些方法可以限制查询重写,如Unnesting of Nested Subqueries一章中所述
子查询取消嵌套将子查询主体取消嵌套并合并到包含它的语句体中,从而允许优化程序在评估访问路径和联接时将它们放在一起考虑。优化器可以解嵌大多数的子查询,除了一些例外的之外的。这些例外包括分层的子查询和包含ROWNUM伪列、集合运算符之一、嵌套聚合函数或对不是子查询的直接外部查询块的查询块的相关引用的子查询。
如上所述,您可以使用Oracle伪列来防止ROWNUM
解嵌子查询:
SQL> WITH data AS (SELECT SYS_GUID() uuid FROM DUAL WHERE ROWNUM >= 1)
2 SELECT uuid, uuid FROM data;
UUID UUID
-------------------------------- --------------------------------
1ADF387E847F472494A869B033C2661A 1ADF387E847F472494A869B033C2661A
发布于 2014-05-13 02:52:18
NO_MERGE提示“修复”了它。防止Oracle重写内联视图。
WITH data AS (SELECT /*+ NO_MERGE */
SYS_GUID () uuid FROM DUAL)
SELECT uuid, uuid
FROM data
NO_MERGE提示指示优化器不要将外部查询和任何内联视图查询组合到单个query.This提示中,这使您可以更好地控制视图的访问方式。
SQL Fiddle with the NO_MERGE hint applied
我仍然在努力理解/阐明查询是如何以这样一种方式重写的,即sys_guid()
将被调用两次。也许这是一个bug;但我倾向于认为这是我自己的想法/代码中的一个bug。
发布于 2014-05-13 22:41:13
非常有趣。
我们可以使用materialize提示将其修复为。
WITH data AS (SELECT /*+materialize*/SYS_GUID () uuid FROM DUAL)
SELECT uuid, uuid
FROM data;
1 F9440E2613761EC8E0431206460A934C F9440E2613761EC8E0431206460A934C
在我看来,如果我们可以仅仅通过添加提示来更改查询的结果,那么就存在Oracle错误。也许我们得让metalink去检查一下。
https://stackoverflow.com/questions/23572605
复制相似问题