首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Oracle中用于计算密集型函数的最快语言

Oracle中用于计算密集型函数的最快语言
EN

Stack Overflow用户
提问于 2012-08-23 15:46:49
回答 2查看 783关注 0票数 2

目前,我们在PL/SQL中有相当多的函数(正规函数,逆函数,Vasicek函数和各种导数),但是它们都是非常慢的。

我可以通过工作站上的数据流获得更好的性能,在工作站上,我已经在C#中编写了代码,然后批量插入结果。然而,这种方法将网络作为瓶颈,如果我能够通过在Oracle DB中具有更快的功能来“把磨在木头上”的话,那就好多了。

我想看看如何通过在c(++)或Java (或任何其他选择)中编写代码来加快速度。这里有人有这方面的经验吗?希望你们中的一个已经尝试过所有的方法,并能解释哪种方法在总体上最有效。

这里的另一个复杂之处是IT正忙着,所以如果我想要放弃在DB上使用某些特性,我需要做一个坚实的案例。我在那个盒子上玩得不多,否则我会那样做的。

我们正在进行Oracle数据库11g企业版发行版11.2.0.2.0-64位的生产

提前谢谢你,

格特-扬

编辑

下面是一个函数的示例,即柯迪的普通民防

这与cume_dist的不同之处在于,cume_dist在一组行中找到了分布。我只需要将概率转换为标准差并返回(很多次),就像Excel中的NORMDISTNORMINV函数一样。

代码语言:javascript
复制
    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

好的,这是基准。有100 K行的测试表。OracleandF#之间的函数是非常直接的相互转换,并给出了相同的结果。

查询:

代码语言:javascript
复制
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函数320 x (!)比Oracle实现更快的是,我真的不明白这种差异是从何而来。任何3-10倍的东西似乎都是合理的。我真的觉得我漏掉了什么。有没有人?

在F#中,我首先将100 k行加载到一个列表中。(似乎是公平的,只是总结一下Oracle中的任何其他列都花费了0.06秒,因此在这两种情况下排除数据访问时间似乎都是公平的。将数据加载到列表中需要花费大约3秒的时间,所以即使包括打开连接、执行和通过网络流等所需的时间,它仍然要快4倍。)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-24 17:44:52

格特-简,

很可能,时间差是由于SQL引擎和PL/SQL引擎之间的上下文切换造成的。函数测试中的100,000行中的每一行都通过PL/SQL例程get_rwa (和/或stdnormal_cdf)。上下文切换涉及保存状态和还原状态,当完成一次时,您可能不会注意到这一点。但这样做的次数是10万倍。

因此,我建议在一个包含100,000行的嵌套表中加载100,000行,并且只将这个嵌套的表传递给一个PL/SQL-例程,该例程执行一个简单的"for I in 1 . nested_table_variable.count循环. end循环“,同时总结各个结果。

另一种选择是在不诉诸PL/SQL的情况下,在SQL中完成所有这些操作。

致以敬意,

罗伯。

票数 4
EN

Stack Overflow用户

发布于 2012-08-23 15:58:03

Oracle支持定义和调用外部过程的能力。假设您可以将C/ C++/ C#应用程序编译为DLL/ .so并将该库移动到数据库服务器,则可以将该DLL的函数公开为外部过程,然后从数据库中调用DLL的函数。因为所有东西都会在同一台机器上运行,所以网络不会成为瓶颈。当然,这意味着您的C/ C++/ C#代码将使用服务器的处理资源--这可能是一件好事,也可能不是一件好事,这取决于服务器的CPU与工作站的CPU相比有多强大,以及服务器正在做什么。

根据您在PL/SQL中对逻辑的具体编码方式,您可能还想考虑利用甲骨文内置的分析函数(如dist )来进行累积分发(我假设这就是您所说的“正态CDF"),或者编写您自己的分析函数。由于您的代码是计算密集型的,因此您也很可能从本地编译中受益。当然,这假设您已经对代码进行了分析,并且没有明显的位置/方法来调整PL/SQL。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12095484

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档