sql - 使用 Oracle 'with' 与使用表的行为不同

标签 sql oracle common-table-expression

尝试了以下代码:

--------------- Setup ------------
drop table suk_rc_t1;

create table suk_rc_t1 (x number, y number);

insert into suk_rc_t1(x) values(1); 

commit;

create or replace function suk_instn_id_wrap(
call_id pls_integer )
 return pls_integer as
begin
  dbms_output.put_line('suk_instn_id_wrap ' || call_id);
  --return suk_instn_id;
  return 123;
end;
/ 

--------------- How many RUNs of suk_instn_id_wrap in 2 queries below ? ------------

select 3 from suk_rc_t1
where (coalesce (y, suk_instn_id_wrap(1)) = suk_instn_id_wrap(2)
       or suk_instn_id_wrap(3) is null);    

begin
   dbms_output.put_line('Done');
end;
/
with suk_rc_t1 as (select 1 x, null y from dual)
select 3 from suk_rc_t1
where (coalesce (y, suk_instn_id_wrap(1)) = suk_instn_id_wrap(2)
       or suk_instn_id_wrap(3) is null);    
begin
   dbms_output.put_line('Done');
end;
/

我期望得到相同的输出。相反,我得到了:

suk_instn_id_wrap 3
suk_instn_id_wrap 1
suk_instn_id_wrap 2
Done

suk_instn_id_wrap 1
suk_instn_id_wrap 2
Done

有人对这种行为有解释吗?

最佳答案

这将是一个优化器的事情,虽然我不能肯定地说我怀疑推理可能如下:

在第一种情况下,Oracle 需要读取数据库以访问列y,如果没有必要,它宁愿不这样做,所以它更愿意评估suk_instn_id_wrap (3) 首先避免读取数据库。当然,事实证明它是假的,所以无论如何都要计算第一个表达式。运气不好。

在第二种情况下,Oracle 知道 y 为空,因此在这种情况下,OR 条件的任何一方都不再需要数据库访问。在这种情况下,它可能默认为表达式的原始顺序。您可能认为第二种情况会更好,因为只有一个函数调用,但也许没有考虑到这一点。

关于sql - 使用 Oracle 'with' 与使用表的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51930887/

相关文章:

sql - 使用 SQL 在 Oracle 模式之间复制数据

sql - order by 时将数值放在底部?

javascript - 如何在 formsweb.cfg 中调用 Javascript?

performance - 如何在子查询因子临时表上创建索引?

SQL Server : Hierarchy recursive CTE with no anchor

mysql - 如何汇总 MySQL 表中的连续行

java - 如何在应用程序启动/加载期间执行 SQL 插入查询以填充数据库?

sql - Oracle 左外连接语法速记符号 (+) 在 HQL 中可用吗?

sql - 与多个表中的一个建立一对一关系

sql - 是否可以使用 CTE 将列值连接成字符串?