Oracle:如何实现*几乎*确定性的功能? [复制]

Posted

技术标签:

【中文标题】Oracle:如何实现*几乎*确定性的功能? [复制]【英文标题】:Oracle: How to implement an *almost* deterministic function? [duplicate] 【发布时间】:2013-11-13 11:53:08 【问题描述】:

我有一个项目,本质上是一批计算。这取决于相当多的参数,虽然它们不是常量(它们可能会随着时间而改变),但它们不会在批处理上下文中改变。

为了清楚起见,想想增值税率:它可能会随着时间的推移而变化,但是当一个会计期间结束时,它在结束本身的问题上表现得就像一个常数。

因为这些参数到处都是,所以我想找到一种方法来尽可能地限制 DB 查找。理想情况下,我会实现一个 DETERMINISTIC 函数,但是,这是不可能的 - 正如相关文档所建议的那样。

有什么想法/建议吗?

提前谢谢你。

编辑: 还要记住,这些值存储在数据库中 - 因为我们可能会保留增值税率,以便我们可以知道它在给定时间点的值。虽然这不是意料之中的,但与之前某个时期有关的批次可能会再次运行 - 并且需要知道其参数的值,因为它们是然后

DETERMINISTIC 函数的好处是,考虑到它产生一致的结果(相同的输入总是给出相同的输出),如果这些值是常量并且我不想跟踪它们,我会这样做.但是文档清楚地指出,如果一个函数进行 db 查找,它绝不能是 DETERMINISTIC。

【问题讨论】:

相关文档建议?你什么意思?您可以使用名为get_parameter 的函数创建一个包,该函数将返回该值。这样,当您想要更改返回值时,您不会使依赖于该函数的对象无效,因为重新编译包体不会导致这种情况。 我改了,希望现在更有意义。您的建议很有趣,但实际上,该值是在数据库中查找的。换句话说,要求这些值将在表单中更改,我发现动态创建包体是有风险的。 所以基本上你想要一个随着时间的推移可能有不同值的值。所以,改变是可能的。您想要的是禁止更改不再是“实际”的值(它是针对前一个时期的),甚至是当前时期的值。您可以创建一个不允许更新该列的触发器,并且您可以编写一个函数(最好的包)来查询表并返回任何给定时间段的值(我猜这个时间段将是这里的参数)。这对你有用吗?毕竟,你永远无法确定有人不会在你背后摆弄数据。 不完全是。我可以肯定在批处理运行期间没有人会弄乱参数(但你的想法是有道理的,也许我应该无论如何都应该实现它)。我只是想避免数据库查找。您可以想象这些参数中的任何一个都将在单个查询中乘以大约 100K 次。我可以依靠 Oracle 来缓存它的值吗? 【参考方案1】:

您无法创建 “几乎” 确定性函数。如果您正确调用它,您可以创建一个确定性函数。如果我们假设您正在创建一个简单的函数来计算增值税金额,您可以通过两种方式进行;首先通过直接在函数中引用表格:

create or replace function calculate_vat is ( 
       P_Sale_Value in number ) return number is

   l_vat number;

begin

   select trunc(vat_rate * P_Sale_Value, 2) into l_vat
     from vat_table
    where ...

   return l_vat;

end;
/

这将被称为:

select sale_value, calculate_vat(sale_value)
  from sales_table

无法将此函数创建为确定性函数,因为表中的值可能会发生变化。作为the documentation says:

不要指定此子句来定义使用包变量或以任何可能影响函数返回结果的方式访问数据库的函数

但是,如果您将增值税值作为参数传递,则可以以不同的方式创建函数:

create or replace function calculate_vat is ( 
       P_Sale_Value in number
     , P_VAT_Rate in number
       ) return number deterministic is

begin    
   return trunc(P_VAT_Rate* P_Sale_Value, 2);    
end;
/

然后您可以在 VAT 表上使用 JOIN 调用它,为您提供有效的确定性函数。

select s.sale_value, calculate_vat(s.sale_value, v.vat_rate)
  from sales_table s
  join vat_table v
    on ...
 where ...

【讨论】:

嗯,这就是我想避免的,因为很可能增值税表上的 JOIN 条件将类似于 'nvl(vat.end_date,sysdate+1) > sysdate' - 反过来可能会对性能产生相当大的负面影响。我知道我不能使用确定性函数。我正在寻找的是一种编写 get_vat 函数的方法,该函数在理想情况下表现得像确定性的。 join 条件不应该有负面的表现,反正比单独查找要好。我刚刚给了你一种方式@theodojo...另一种方式是sub-query caching or global variables。 这就是我想要的。我猜子查询缓存也可以与 WITH 子句一起使用? 是的,它会@theodojo。

以上是关于Oracle:如何实现*几乎*确定性的功能? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

QComboBox实现复选功能(三种方法:嵌套QListWidget, 设置QStandardItemModel, 设置Delegate)

如何有效地确定多边形是凸面、非凸面还是复面?

为DataGridView控件实现复选功能

UE4 C++EasySurvivalRPG项目功能复刻

如何从 Oracle 表中获取几乎匹配的字符串?

如何在雪花中实现 NUMBER(Oracle) 数据类型功能?