現在、かなりの数の関数 (通常の CDF、逆 CDF、Vasicek、およびあらゆる種類の派生関数) が PL/SQL でコーディングされていますが、それらは非常に遅いです。
C# でコーディングしたワークステーションを介してデータをストリーミングし、結果を一括挿入することで、パフォーマンスを大幅に向上させることができます。ただし、このアプローチではネットワークがボトルネックのままになります。Oracle DB 内でより高速な機能を使用して、「木材がある場所に工場を置く」ことができれば、はるかに優れています。
c(++)またはJava(または他の代替手段)でコーディングすることにより、それをどのように高速化できるかを確認したいと思います。ここにいる人はこれについて何か経験がありますか?うまくいけば、あなたの 1 人がすべてのアプローチを試し、どれが全体的に最も効果的であったかを説明できます。
ここでさらに複雑なことは、IT が忙しいということです。そのため、DB で何らかの機能を使用する権利を放棄したい場合は、確固たる主張をする必要があります。私はそのボックスであまり遊ぶことができません。そうでなければ、そうするでしょう。
私たちは、Oracle Database 11g Enterprise Edition リリース 11.2.0.2.0 - 64 ビット製品を使用しています。
前もって感謝します、
ゲルト・ヤン
編集
これは、 Cody による通常の CDFである関数の例です。
これと の違いは、一連の行内の分布cume_dist
を見つけることです。Excelのand関数cume_dist
のように、確率を標準偏差に変換して戻す必要があります (何度も) 。NORMDIST
NORMINV
function stdnormal_cdf(u number) return number is
z number;
y Number;
begin
y:=abs(u);
if y <= 0.6629126073623883041257915894732959743297 then
z:=y * y;
y:=u * ((((1.161110663653770e-002 * z + 3.951404679838207e-001) * z + 2.846603853776254e + 001) * z + 1.887426188426510e + 002) * z + 3.209377589138469e + 003)/((((1.767766952966369e-001 * z + 8.344316438579620) * z + 1.725514762600375e + 002) * z + 1.813893686502485e + 003) * z + .044716608901563e + 003);
return 0.5 + y ;
else
z:=exp(-y * y/2)/2;
if y <= 5.65685424949238019520675489683879231428 then
y:=y/1.41421356237309504880168872420969807857;
y:=((((((((2.15311535474403846e-8 * y + 5.64188496988670089e-1) * y + 8.88314979438837594) * y + 6.61191906371416295e01) * y + 2.98635138197400131e02) * y + 8.81952221241769090e02) * y + 1.71204761263407058e03) * y + 2.05107837782607147e03) * y + 1.23033935479799725e03)/((((((((1.00000000000000000e00 * y + 1.57449261107098347e01) * y + 1.17693950891312499e02) * y + 5.37181101862009858e02) * y + 1.62138957456669019e03) * y + 3.29079923573345963e03) * y + 4.36261909014324716e03) * y + 3.43936767414372164e03) * + 1.23033935480374942e03);
y:=z * y;
else
z:=z * 1.41421356237309504880168872420969807857/y;
y:=2/(y * y);
y:=y * (((((1.63153871373020978e-2 * y + 3.05326634961232344e-1) * y + 3.60344899949804439e-1) * y + 1.25781726111229246e-1) * y + 1.60837851487422766e-2) * y + 6.58749161529837803e-4)/(((((y + 2.56852019228982242) * y + 1.87295284992346047) * y + 5.27905102951428412e-1) * y + 6.05183413124413191e-2) * y + 2.33520497626869185e-3);
y:=z * (1/1.77245385102123321827450760252310431421-y);
end if;
if u < 0 then
return y;
else
return 1-y;
end if;
end if;
end;
編集2
わかりましたので、ここにベンチマークがあります。100k 行のテスト テーブル。Oracle と F# の間の関数は、お互いをかなり単純に変換したものであり、同じ結果が得られます。
クエリ:
select
sum(get_rwa(approach, exposure_class_code, pd_r, lgd_r, ead_r, maturity_r, net_sale, rwf_r))
from functest
- 解釈: 12.8 秒
- ネイティブ: 13.2 秒
- .Net (F#): 0.04 秒。
これにより、.Net 関数は Oracle の実装よりも 320 倍 (!) 高速になります。この違いがどこから来るのか、私には本当にわかりません。3 倍から 10 倍までは妥当と思われます。ここで何かが欠けていると本当に思います。誰?
F# では、最初に 100k 行を List にロードしました。(公平に見えました。Oracleの他の列を合計すると0.06秒かかるため、どちらの場合もデータアクセス時間を除外するのが公平に思えました。データをリストにロードするのに約3秒かかるため、時間を含めても接続を開き、実行し、ネットワーク経由でストリーミングする必要がありますが、それでも 4 倍高速です。)