2

現在、かなりの数の関数 (通常の 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のように、確率を標準偏差に変換して戻す必要があります (何度も) 。NORMDISTNORMINV

    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 倍高速です。)

4

2 に答える 2

6

Oracleは、外部プロシージャを定義および呼び出す機能をサポートしています。C / C ++ / C#アプリケーションをDLL / .soにコンパイルし、そのライブラリをデータベースサーバーに移動できると仮定すると、DLLの関数を外部プロシージャとして公開し、データベース内からDLLの関数を呼び出すことができます。すべてが同じマシンで実行されるため、ネットワークがボトルネックになることはありません。もちろん、これは、C / C ++ / C#コードがサーバーの処理リソースを使用していることを意味します。これは、サーバーのCPUがワークステーションのCPUと比較してどれだけ強力であるか、およびサーバーが他に何であるかによって、良い場合とそうでない場合があります。やっています。

PL / SQLでロジックをコーディングした方法に応じて、累積分布関数にcume_distなどのOracleの組み込み分析関数を利用するか(「正規CDF」の意味であると想定しています)、独自の分析関数を作成します。コードは計算量が多いため、ネイティブコンパイルの恩恵を受ける可能性もかなりあります。もちろん、これは、コードのプロファイルを作成し、PL/SQLを調整するための明確な場所/アプローチがないことを前提としています。

于 2012-08-23T15:58:03.300 に答える