代码之家  ›  专栏  ›  技术社区  ›  Ed Heal

使用Oracle“with”与使用表的行为不同

  •  3
  • Ed Heal  · 技术社区  · 6 年前

    尝试了以下代码:

    --------------- 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
    

    有人能解释这种行为吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   rghome    6 年前

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

    在第一种情况下,Oracle需要读取数据库才能访问列 y ,如果不需要,它宁愿不这样做,所以它宁愿 evaluate suk_instn_id_wrap(3)

    在第二种情况下,甲骨文知道 是的 是空的,所以在这种情况下 OR 条件在数据库访问方面的成本会更高。在这种情况下,它可能默认为表达式的原始顺序。您可能认为第二个条件会更好,因为只有一个函数调用,但可能不考虑这一点。