Oracle SQL:在内联视图中出现时,了解SYS_GUID()的行为?

Bri*_*ian 18 sql oracle

这是有问题的示例SQL; SQL应该在任何Oracle DBMS上运行(我运行的是11.2.0.2.0).

注意尽管是在内联视图/ with子句中构建的,但结果集中的UUID值是如何不同的(一个具有898,另一个具有899).在下面你可以看到DBMS_RANDOM.RANDOM()没有这种副作用.

SQL:

WITH data AS (SELECT SYS_GUID () uuid FROM DUAL)
    SELECT uuid, uuid
      FROM data
Run Code Online (Sandbox Code Playgroud)

输出:

UUID                                      UUID_1
F8FCA4B4D8982B55E0440000BEA88F11      F8FCA4B4D8992B55E0440000BEA88F11
Run Code Online (Sandbox Code Playgroud)

在Contrast DBMS_RANDOM中 ,结果是相同的

SQL:

WITH data AS (SELECT DBMS_RANDOM.RANDOM() rand FROM DUAL)
SELECT rand, rand
  FROM data
Run Code Online (Sandbox Code Playgroud)

输出:

RAND    RAND_1
92518726    92518726
Run Code Online (Sandbox Code Playgroud)

更有趣的是我可以通过包含对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
Run Code Online (Sandbox Code Playgroud)

稳定SYS_GUID的SQL小提琴:http://sqlfiddle.com/#!4/d41d8/29409

SQL Fiddle显示奇怪的SYS_GUID行为:http://sqlfiddle.com/#!4/d41d8/29411

Vin*_*rat 6

文件给出了一个理由,为什么你会看到一个差异(重点煤矿):

警告:

因为SQL是一种声明性语言,而不是命令式(或程序性)语言,所以你不知道SQL语句调用的函数将运行多少次 - 即使该函数是用PL/SQL(一种命令式语言)编写的.如果您的应用程序要求函数执行一定次数,请不要从SQL语句调用该函数.请改用光标.

例如,如果应用程序要求为每个选定的行调用函数,则打开游标,从游标中选择行,然后为每一行调用函数.此技术保证对函数的调用次数是从游标获取的行数.

基本上,Oracle没有指定在sql语句中调用函数的次数:它可能取决于发布,环境,访问路径以及其他因素.

但是,有一些方法可以限制查询重写,如嵌套子查询的Unnesting一章所述:

子查询不需要的东西,并将子查询的主体合并到包含它的语句的主体中,允许优化器在评估访问路径和连接时将它们一起考虑.除了一些例外,优化器可以取消大多数子查询.这些异常包括分层子查询和包含ROWNUM伪列的子查询,集合运算符之一,嵌套聚合函数或对查询块的相关引用,该查询块不是子查询的直接外部查询块.

如上所述,您可以使用ROWNUM伪列来阻止Oracle取消子查询:

SQL> WITH data AS (SELECT SYS_GUID() uuid FROM DUAL WHERE ROWNUM >= 1)
  2  SELECT uuid, uuid FROM data;

UUID                             UUID
-------------------------------- --------------------------------
1ADF387E847F472494A869B033C2661A 1ADF387E847F472494A869B033C2661A
Run Code Online (Sandbox Code Playgroud)