Oracle - 使用params重用SELECT

时间:2018-04-13 09:06:06

标签: sql oracle plsql

我有SELECT喜欢

SELECT t1.A,
       t2.A,
       t1.B,
       t2.B, 
       case when v_val2 < sysdate 
            then null 
            else t2.D 
      end
from t1
left join t2
   on t1.C = t2.C and t2.D = p_val1
where t2.ref_date = p_val2

其中 p_val1 p_val2 是params。真正的SELECT更复杂,并且连接表有1.4亿行或更多。

如何在多个地方重复使用此选择?现在我在Business Object Report,VIEW,Insert和spool文件中使用它。我试图创建VIEW但没有params它太慢了。

我搜索了使用参数查看的内容,但是在问{TOM}中的this主题中,结论是没有这样的内容。

更新

p_val1 可以是4个固定值(如'A','B','C','D'),但 p_val2 更复杂,因为它是加载日期(加载数据的日期)。大约有500个历史加载日期,之后加载成为每日。每个报告,输出等都必须按日期进行。

3 个答案:

答案 0 :(得分:3)

您的查询没有什么复杂的。我认为没有理由为什么在使用相同的标准调用时,视图应该比原始查询慢。

视图没有参数:

create view my_view as
  select 
    t2_d, t2_ref_date,
    t1.a as t1_a, t2.a as t2_a, t1.b as t1_b, t2.b as t2_b,
    case when v_val2 < sysdate then null else t2.d end as e
  from t2
  join t1 on t1.c = t2.c;

当在查询中使用时,它应该导致相同的执行计划和与原始查询相同的性能:

select t1_a, t2_a, t1_b, t2_b, e
from my_view
where t2_ref_date = p_val2
  and t2_d = p_val1;

你真的尝试过吗?我真的无法想象为什么这应该慢一些。

DBMS可以通过ref_dateD访问T2记录,然后加入T1。因此我改变了FROM子句中表的顺序如下。 (我已经在上面的视图中做了这个。)这只是为了便于阅读。它仍然是同一个查询。

SELECT 
  t1.A,
  t2.A,
  t1.B,
  t2.B, 
  case when v_val2 < sysdate then null else t2.D end
from t2
join t1 on t1.C = t2.C
where t2.ref_date = p_val2
  and t2.D = p_val1

要使此查询快速运行,我建议使用以下索引:

create index idx_t2 on t2(ref_date, d, c);
create index idx_t1 on t2(c);

甚至更好地覆盖索引:

create index idx_t2 on t2(ref_date, d, c, a, b);
create index idx_t1 on t2(c, a, b);

当然,您的真实查询可能会有所不同。不是因为有很多行或很多表,但在您的示例中,我可以轻松选择有问题的两列。因此优化器可以直接使用它们来应用WHERE子句。但是,如果您的查询包含子查询中的聚合,例如在聚合之前应用条件的情况,则无法再使用视图提前应用它。

在不知道真实查询的情况下提供建议很难。也许编写流水线函数对你来说是更好的选择。

答案 1 :(得分:1)

创建功能。你可以在多个地方使用

CREATE OR REPLACE FUNCTION SampleFunction1(p_val1 in varchar2,p_val2 in varchar2 )

          RETURN sys_refcursor
        is
          l_rc sys_refcursor;
        begin
          open l_rc
           for        

        SELECT t1.A,t2.A,t1.B,t2.B, case when v_val2 < sysdate then null else t2.D end
        from t1
        join t2
           on t1.C = t2.C and t2.D = p_val1
        where t2.ref_date = p_val2;
          return l_rc;
        end;

答案 2 :(得分:0)

我的回答(最接近我并清楚我并且可能不是最佳选择)是创建用户定义的类型和第一类型的表格,如:

CREATE TYPE my_type AS OBJECT
    ( a        VARCHAR2(20)
    , b    VARCHAR2(20)
    , c     VARCHAR2(20)
    , d    VARCHAR2(20)
    , e     VARCHAR2(20)
    ) ;

输入 my_type 的类型:

create TYPE T_my_type  AS TABLE OF my_type ;

之后(感谢@ user9405863)我创建了返回 T_my_type 的函数(而不是 sys_refcursor ):

create or replace function myFunc(p_val1 varchar2, p_val2 date)
RETURN T_my_type  is

v_T_my_type T_my_type ;

BEGIN

  SELECT my_type (t1.A,t2.A,t1.B,t2.B, case when v_val2 < sysdate then null else t2.D end)
  BULK collect INTO v_T_my_type 
from t1
join t2
   on t1.C = t2.C and t2.D = p_val1
where t2.ref_date = p_val2;

  RETURN ttv_T_my_type 

END;

在该功能中,我只是将结果列投射到 my_type ,并使用 BULK收集INTO 获得结果。

最后,当我执行:

select *
from table(myFunc('A', '13.04.2018'));

结果是我的预期。

<强> COMMENT

如果你说出你对这个解决方案的看法以及它的利弊,我会很高兴。