首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Oracle SQL:理解SYS_GUID()出现在内联视图中时的行为?

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

Stack Overflow用户
提问于 2014-05-10 03:36:14
回答 3查看 1.4K关注 0票数 19

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

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

SQL:

代码语言:javascript
运行
复制
WITH data AS (SELECT SYS_GUID () uuid FROM DUAL)
    SELECT uuid, uuid
      FROM data

输出:

代码语言:javascript
运行
复制
UUID                                      UUID_1
F8FCA4B4D8982B55E0440000BEA88F11      F8FCA4B4D8992B55E0440000BEA88F11

DBMS_RANDOM结果是一样的。

SQL:

代码语言:javascript
运行
复制
WITH data AS (SELECT DBMS_RANDOM.RANDOM() rand FROM DUAL)
SELECT rand, rand
  FROM data

输出:

代码语言:javascript
运行
复制
RAND    RAND_1
92518726    92518726

更有趣的是,我可以通过包含对DBMS_RANDOM.RANDOM的调用来更改行为/稳定sys_guid:

代码语言:javascript
运行
复制
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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-05-14 22:52:12

您可能会看到差异的原因的documentation gives a reason (强调我的):

警告:

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

例如,如果应用程序要求为每个选定行调用函数,则打开游标,从游标中选择行,然后为每行调用该函数。此技术可确保对函数的调用次数等于从游标中提取的行数。

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

但是,有一些方法可以限制查询重写,如Unnesting of Nested Subqueries一章中所述

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

如上所述,您可以使用Oracle伪列来防止ROWNUM解嵌子查询:

代码语言:javascript
运行
复制
SQL> WITH data AS (SELECT SYS_GUID() uuid FROM DUAL WHERE ROWNUM >= 1)
  2  SELECT uuid, uuid FROM data;

UUID                             UUID
-------------------------------- --------------------------------
1ADF387E847F472494A869B033C2661A 1ADF387E847F472494A869B033C2661A
票数 7
EN

Stack Overflow用户

发布于 2014-05-13 02:52:18

NO_MERGE提示“修复”了它。防止Oracle重写内联视图。

代码语言:javascript
运行
复制
WITH data AS (SELECT /*+ NO_MERGE */
                    SYS_GUID () uuid FROM DUAL)
SELECT uuid, uuid
  FROM data

From the docs:

NO_MERGE提示指示优化器不要将外部查询和任何内联视图查询组合到单个query.This提示中,这使您可以更好地控制视图的访问方式。

SQL Fiddle with the NO_MERGE hint applied

我仍然在努力理解/阐明查询是如何以这样一种方式重写的,即sys_guid()将被调用两次。也许这是一个bug;但我倾向于认为这是我自己的想法/代码中的一个bug。

票数 4
EN

Stack Overflow用户

发布于 2014-05-13 22:41:13

非常有趣。

我们可以使用materialize提示将其修复为。

代码语言:javascript
运行
复制
WITH data AS (SELECT /*+materialize*/SYS_GUID () uuid FROM DUAL)
    SELECT uuid, uuid
      FROM data;

1   F9440E2613761EC8E0431206460A934C    F9440E2613761EC8E0431206460A934C

在我看来,如果我们可以仅仅通过添加提示来更改查询的结果,那么就存在Oracle错误。也许我们得让metalink去检查一下。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23572605

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档