我需要有关优化查询的帮助。
我有一个包含许多帐户类型列和相应值的表
如果 accounttype1 包含帐号ID为“2000”且对应值为 chargeamount1 ,则 accounttype1 包含帐号ID“ 2500“,相应的值在 chargeamount2 等等。
我必须通过汇总相应的chargeamount值来获取所有帐户类型列中指定帐户类型的总和。我试图通过如下所示的函数实现这一目标......
select msisdn,
fn_get_acc_amount ('2000', accounttype1, chargeamount1, accounttype1_a, chargeamount1_a, accounttype2, chargeamount2, accounttype2_a,
chargeamount2_a,accounttype3, chargeamount3,accounttype3_a,chargeamount3_a
)data_account_4508_usage
from data_cdr partition (p20160521)
功能:
CREATE OR REPLACE function fn_get_acc_amount(p_account varchar2,
p_accounttype1 varchar2, p_chargeamount1 varchar2,p_accounttype1_a varchar2, p_chargeamount1_a varchar2,
p_accounttype2 varchar2, p_chargeamount2 varchar2,p_accounttype2_a varchar2, p_chargeamount2_a varchar2,
p_accounttype3 varchar2, p_chargeamount3 varchar2,p_accounttype3_a varchar2, p_chargeamount3_a varchar2)
return number as
v_accum number := 0;
begin
if p_accounttype1 = p_account then
v_accum := v_accum + to_number(nvl(p_chargeamount1,0));
end if;
if p_accounttype1_a = p_account then
v_accum := v_accum + to_number(nvl(p_chargeamount1_a,0));
end if;
if p_accounttype2 = p_account then
v_accum := v_accum + to_number(nvl(p_chargeamount2,0));
end if;
if p_accounttype2_a = p_account then
v_accum := v_accum + to_number(nvl(p_chargeamount2_a,0));
end if;
if p_accounttype3 = p_account then
v_accum := v_accum + to_number(nvl(p_chargeamount3,0));
end if;
if p_accounttype3_a = p_account then
v_accum := v_accum + to_number(nvl(p_chargeamount3_a,0));
end if;
return nvl(v_accum,0);
end;
/
在我的IDE上运行并返回一个值...但是必须创建或将输出插入到另一个表中,因为表data_cdr有大约3000万条记录。
以下是我尝试优化功能:
CREATE OR REPLACE function fn_get_acc_amount(
p_account varchar2,
p_accounttype1 varchar2, p_chargeamount1 varchar2,p_accounttype1_a varchar2, p_chargeamount1_a varchar2,
p_accounttype2 varchar2, p_chargeamount2 varchar2,p_accounttype2_a varchar2, p_chargeamount2_a varchar2,
p_accounttype3 varchar2, p_chargeamount3 varchar2,p_accounttype3_a varchar2, p_chargeamount3_a varchar2)
return number
result_cache
is
v_accum number;
v_sql varchar2 (4000);
begin
v_accum :=0;
v_sql:='with acc_table as
(
select :1 accounttype, nvl(:2,0) chargeamount from dual union all
select :3, nvl (:4,0 ) from dual union all
select :5, nvl (:6,0 ) from dual union all
select :7, nvl (:8,0 ) from dual union all
select :9, nvl (:10,0 ) from dual union all
select :11, nvl (:12,0 ) from dual
)
select sum(chargeamount) from acc_table
where accounttype ='||p_account;
execute immediate v_sql into v_accum
using p_accounttype1 , p_chargeamount1 ,p_accounttype1_a , p_chargeamount1_a ,
p_accounttype2 , p_chargeamount2 ,p_accounttype2_a , p_chargeamount2_a ,
p_accounttype3 , p_chargeamount3 ,p_accounttype3_a , p_chargeamount3_a ;
return nvl(v_accum,0);
end;
/
它仍在继续运行。 我需要建议,我可以优化这一点。我试过寻找枢轴查询,但我无法让它工作。
我将非常感激我能获得的任何见解。
答案 0 :(得分:1)
直接的SQL语句几乎可以肯定比在函数中执行的任何操作(更快)运行 - 特别是如果您一次读取一行。
这样的事情可能有用:
select [whatever other columns,]
case p_accounttype1 when '2000' then p_chargeamount1 else 0 end +
case p_accounttype1_a when '2000' then p_chargeamount1_a else 0 end +
case p_accounttype2 when '2000' then p_chargeamount2 else 0 end +
case p_accounttype2_a when '2000' then p_chargeamount2_a else 0 end +
case p_accounttype3 when '2000' then p_chargeamount3 else 0 end +
case p_accounttype3_a when '2000' then p_chargeamount3_a else 0 end
as data_account_4508_usage
from [......]
或者,如果你需要所有列中这些总和的总和(我无法从叙述中看出来并且我没有阅读你的函数,抱歉) - 你可以将整个案例表达式的总和包装在一个大的外部SUM()。
如果您需要针对不同的帐户ID运行此变量,可以为'2000'插入绑定变量。
话虽如此,如果您的组织中有任何权力,您应该强烈主张规范化您的数据模型。你不应该为了最简单的查询之一而跳过这样的箍。祝你好运!
答案 1 :(得分:0)
我的第一个想法是改变你的查询:
select msisdn, sum(amount) from (
select msisdn, chargeamount1 as amount from data_cdr partition (p20160521) where accounttype1 = '2000' and chargeamount1 is not null
union all
select msisdn, chargeamount1_a from data_cdr partition (p20160521) where accounttype1_a = '2000' and chargeamount1_a is not null
union all
select msisdn, chargeamount2 from data_cdr partition (p20160521) where accounttype2 = '2000' and chargeamount2 is not null
union all
select msisdn, chargeamount2_a from data_cdr partition (p20160521) where accounttype2_a = '2000' and chargeamount2_a is not null
union all
select msisdn, chargeamount3 from data_cdr partition (p20160521) where accounttype3 = '2000' and chargeamount3 is not null
union all
select msisdn, chargeamount3_a from data_cdr partition (p20160521) where accounttype3_a = '2000' and chargeamount3_a is not null
) as tmp
group by msisdn
当然,您的金额列是整数(不是字符串),并且您在每个帐户类型列上都有不同的索引以及所有需要的字段