一尘不染

Oracle SQL:如果在嵌入式视图中显示SYS_GUID()的行为,该如何理解?

sql

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

请注意,尽管UUID值是从内联view /
with子句中构建的,但结果集中的UUID值却有所不同(一个为898,另一个为899)。在下面的更多内容中,您可以看到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小提琴:http
://sqlfiddle.com/#!4/d41d8/29409

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


阅读 127

收藏
2021-03-17

共1个答案

一尘不染

文档给出了为什么您可能会看到差异(强调我的意思)的原因:

警告:

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

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

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

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

子查询取消嵌套,将其嵌套并合并到包含该子查询的语句主体中,从而使优化程序在评估访问路径和联接时将它们一起考虑。 除了某些例外
,优化器可以取消嵌套大多数子查询。这些例外包括层次结构子查询和包含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
2021-03-17