目前我们有相当多的函数(正常 CDF、逆 CDF、Vasicek 和各种派生类)用 PL/SQL 编码,但它们非常慢。
我可以通过在工作站上流式传输数据来获得更好的性能,在该工作站上我用 C# 编码了一些东西,然后将结果批量插入回来。然而,这种方法使网络成为瓶颈,如果我可以通过在 Oracle DB 中拥有更快的功能来“将工厂放在木材所在的地方”,那就更好了。
我想看看如何通过在 c(++) 或 Java(或您可能拥有的任何其他替代方案)中对其进行编码来加快速度。这里有人有这方面的经验吗?希望你们中的一个人已经尝试了所有方法,并且可以解释哪种方法总体上效果最好。
这里额外的复杂性是 IT 很忙,所以如果我想放弃使用数据库上的某些功能,我需要做一个可靠的案例。我不能在那个盒子上玩太多,否则我会那样做。
我们正在使用 Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
提前致谢,
格特-扬
编辑
这是一个函数的示例,它是Cody 的 Normal CDF。
this 和 the 之间的区别在于cume_dist
找到cume_dist
一组行内的分布。我只需要将概率转换为标准偏差并返回(很多次),就像Excel 中的NORMDIST
and函数一样。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 行加载到列表中。(看起来很公平,只是总结 Oracle 中的任何其他列花费 0.06 秒,因此在这两种情况下排除数据访问时间似乎很公平。将数据加载到列表中大约需要 3 秒,所以即使我包括时间它需要打开连接,通过网络执行和流式传输等,然后它仍然快 4 倍。)