2016-05-24 5 views
1

クエリを最適化するための助けが必要です。Oracleクエリの最適化:列全体の合計

accounttype1は、アカウントIDが「2000」と言う含まれており、accounttype1は、アカウントIDが含まれている場合、対応する値は、chargeamount1である場合、私は多くのアカウントの種類の列と対応する値

を持つテーブルを持っています「2500」とし、対応する値はchargeamount2などにあります。

enter image description here

私は、対応する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) 

機能:

これが実行され、値を返す...しかし、作成したり、挿入した私のIDEに
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; 
/

表data_cdrには約3,000万レコードがあるため、別の表への出力はこれまで以上に必要です。それはまだ永遠に実行されている

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

私が持っている最初のアイデアは、このようなあなたのクエリを変更することです:もちろんの

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 

あなたの金額の列は整数(文字列ではありません)であり、あなたが必要なすべてのフィールドを持つすべてのaccounttype列に異なるインデックスを持つ

+0

これは私にとってあなたがしたことがちょうど1つの勘定科目勘定(2000)のためであるかのように、私は本当に切れません...私は15勘定まで行う必要があります....別のサブクエリを取得し、後でmsisdnにすべて参加する必要がありますか? – Oxax

+0

@Oxax IN(#、#...)を使用することができます –

1

ストレートSQL文は、関数内で実行可能な処理(特に、一度に1つずつ行を読み取る場合)よりも高速(ほとんど)高速です。このような

何かが動作することがあります。

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

ありがとうございました。あなたが気づいたように、それは純粋なSQLです。私はそれを試して、あなたにパフォーマンスを知らせるでしょう。カントはコールデータレコード(cdr)であり、彼らが私たちに送られるので、正規化について多くを行います。多くの正規化されていない列で区切られたパイプ。それはデータウェアハウスデータベースであり、データの正規化解除はベストプラクティスとみなされます。 – Oxax