尝试了以下代码:
--------------- 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/