最佳做法

下面是一些设计业务规则的最佳做法,包括正确命令的使用、语法的使用、优化准则、建议的计算级别、聚合选项和调试方法。

环境设置

在使用指示业务规则如何执行计算的命令时,请考虑以下最佳做法。
  • SET UPDATECALC OFF 可关闭智能计算,最适用于使用跨维运算符且可能有多个用户访问相同数据块组合的业务规则。此命令最适用于多个用户向数据库写入的应用。如果您使用智能计算,请确保该计算能够得到预期的结果。
  • 对于版本为标准目标或者使用了非叶数据区域且在计算过程中无法排除这些数据区域的应用,应设置 SET AGGMISSG OFF

    如果应用程序设计具有标准自下而上版本的安装程序(在 0 级加载数据),使用 SET AGGMISSG ON 比较好。

  • SET NOTICESET MSG SUMMARY 只应在开发环境中用于单个计算分析。在生产环境中或在计算分析完成后,应删除这些命令。
  • 当 FIX 语句中包含运行时提示 (RTP) 时,应使用 SET EMPTYMEMBERSETS ON,以避免计算空集。这可防止在集合为空时对所有成员运行计算。

优化和性能注意事项

  • 在业务规则中使用模板,以避免重复代码部分并充分利用 RTP。
  • 检查每次计算中对动态计算成员的相关性。如有可能,对计算进行更改以避免重复使用动态计算或删除动态计算。
  • 使用 FIX 和 IF 语句集中计算,以确保仅计算所需的数据。
  • 避免创建 0(零)数据结果,除非您希望看到零;例如,用于库存水平。这会创建一个块,该块包含在所有 FIX 和 IF 语句中并会进行计算。如有可能,在数据加载时删除零,或在业务规则中阻止创建零。
  • 尽量避免在用于检查条件是否存在的 IF 语句中使用布尔逻辑。例如,将
    IF (("Budget" ==#missing) OR ("Budget" ==0))
    替换为以下内容,可提供相同结果但会避免使用布尔逻辑:
    IF ("Budget" +1==1) or IF (Budget/Budget ==#missing)
  • 尽可能在执行稀疏计算前执行密集计算。密集计算不会创建块,但稀疏计算会创建块。在执行聚合时,例如,要获得分配计算的合计,请确保仅对该分配计算所需的数据部分求和。
  • 将对数据库的计算遍数降至最低。
  • 避免递归公式。过度的递归会造成性能问题,并且可能需要清除一些值才能得到一致的结果。

避免递归错误

递归错误的主要原因是密集动态计算没有包括在列标题中、包括 FIX 语句中未包含成员、同时进行计算。如果其他一些动态计算成员的公式在 FIX 语句中包含密集成员,则会发生递归。如果递归超过 128 级,则会出现递归错误。

排除动态计算成员的主要原因是为了提高性能。此外,排除动态计算成员可以确保导出使用压缩块而不是扩展块,从而帮您避免递归错误。还可以通过更改用作为列标题的密集维来避免递归错误,对于列标题,FIX 语句定义的每个列都是单独计算的。这样便不会出现递归,因为没有包含在 FIX 语句中的其他密集动态计算将被忽略,从而使规则能够成功运行。

注:

如果导出文件包含的列超过 256 个,则无法更改密集维列标题。

例如,如果使用以下计算脚本,您会遇到无法计算。Essbase 错误(1200494): 执行 [Yield%] 的公式时出错 (第 15 行): 达到了递归限制 [128] 错误:

SET DataExportOptions
     {
     DATAEXPORTCOLFORMAT ON;
     DATAEXPORTDIMHEADER ON;
     DATAEXPORTDRYRUN OFF;
     DataExportRelationalFile OFF;
     DataExportNonExistingBlocks OFF;
     DataExportLevel ALL;
     DATAEXPORTCOLHEADER "Period";
     DATAEXPORTOVERWRITEFILE ON;
     DataExportDynamicCalc ON;
     };

FIX ("Yield%",@Relative("Change Over",0),@Relative("Currency",0),@Relative("Entity",0),@Relative("Product",0),@Relative("CostCentre",0),"Jan","Actual_Total",@Relative("View",0),"Working","Fy20")

DATAEXPORT "File" "," "/u03/inbox/data/ExportDataFile.txt"  "#";
 

要避免此错误,请将 DataExportDynamicCalc ON; 更改为 DataExportDynamicCalc OFF; 来关闭“动态”选项。

使用 FIX 语句

  • FIX 语句用于聚焦业务规则(将计算的块数保持在尽可能低的水平),以确保仅计算所需的块。
  • 建议将 FIX 语句用于稀疏维,因为该语句可减少需要计算的块数。
  • 如果应用程序设计具有自下而上版本的安装程序,请确保在所有维的 0 级完成计算。
  • 尽可能在稀疏维上使用外部 FIX 语句,在密集维上使用内部 IF 语句。
  • 所有 FIX 语句都应包括除计算范围以外的所有维的成员。如果将某个维排除,则也包括来自该维的所有成员。这可能没有必要。
  • 尽可能使用嵌套 FIX 语句来减少数据库计算遍数。每个完整 FIX 语句都需要对数据库计算一遍。例如,可以对版本、方案和在整个业务规则中都是静态的任何其他维选择使用外部 FIX。
  • 对于与 Web 表单关联的业务规则,利用 FIX 语句中选择的页面和 POV 成员可减少计算的块数。

使用 IF 语句

  • IF 语句可用于成员公式中;但 FIX 语句不能。
  • IF 语句应在 FIX 语句内使用以减少要访问的块数。IF 语句会将 FIX 中的所有块放入内存中。
  • 尽可能在稀疏维上使用外部 FIX 语句,在密集维上使用内部 IF 语句。
  • 尽可能使用 ELSE 而非 NOT 与 ELSEIF 的组合,以避免在计算过程中对成员值进行不必要的分析。如非必要,不要使用 ELSE 语句。
  • 检查“计算成员块”选项,以确定是否可以使用没有动态计算相关性的稀疏成员。
  • 如有可能,对 IF 语句进行排序,大多数情况下会遇到块中的第一个 IF。如果适用,请在 IF 中使用 NOT 来确保这一点。

    请考虑以下脚本,其中假设 SalesYTDSample.BasicRatios 的子代(其中帐户时间是密集维)。

    SET UPDATECALC OFF;
    "SalesYTD"(
    IF(@ismbr("Jan"))
        "SalesYTD" = "Sales";
    Else
        "SalesYTD"="Sales" + @prior("SalesYTD");
    Endif)

    在此示例中,12 个月中有 11 个月的数据满足 ELSE 条件,而只有 1 个月的数据满足 IF 条件。此外,SalesYTD 成员是在单元格模式下计算的,这意味着无论 IF 顺序如何都会先计算 January,因为它首先出现在大纲中。可以在 IF 语句中使用 NOT 来优化此脚本,如下例所示:

    SET UPDATECALC OFF;
    "SalesYTD"(
    IF(NOT(@ismbr("Jan")))
        "SalesYTD" = "Sales" + @prior("SalesYTD");
    Else
        "SalesYTD"="Sales";
    Endif)

块计算

  • 使用 RTP 确保业务规则中仅包含所需的数据。
  • 仅聚合或计算在每个计算阶段所需的数据,以尽可能长久地确保计算中包含尽可能少的块数。

计算级别

  • 如果应用程序设计具有自下而上版本的安装程序,请确保在所有维的 0 级完成计算。
  • 如果只是出于审批流程的需要,请在 BSO 规划类型中包含聚合。将所有其他聚合移动到 ASO 规划类型。
  • 尽可能长久地保持计算中包含尽可能少的块数。

语法注意事项

  • 如果对整个维使用语法,请始终使用 @LEVMBRS,而不是 @RELATIVE
  • 如果适用,请使用 @CHILDREN,而不是 @RELATIVE
  • 如果只是想从 FIX 语句中排除某些成员,请使用 @REMOVE@LEVMBRS
使用 Planning 中存储的日期执行计算

Planning 允许您输入日期值。例如,使用 MM/DD/YYYY 格式,可将开始日期输入为 11/01/2019,将结束日期输入为 06/01/2020。Essbase 会将日期格式的值存储为数值。例如,前面的开始日期会存储为 20191101,结束日期会存储为 201200601。可以使用 Essbase 函数(例如,@ROUND@INT@TRUNCATE 函数)计算任何开始日期和结束日期之间的月数。以下示例显示了如何使用 @ROUND 函数计算开始日期和结束日期之间的月数:

  1. 计算结束日期年份和开始日期年份之间月数的方式如下:
    (@ROUND ("End Date",-4) - @ROUND ("Start Date",-4))/10000*12
    此计算 (20200000 – 20190000)/10000 *12 的结果为 12。
  2. 计算结束日期年份的开始日期和结束日期之间的月数,然后加上此数。
    (@ROUND ("End Date",-2) - @ROUND ("End Date",-4))/100
    计算 (20200600 – 20200000)/100 的结果为 6。
  3. 计算开始日期年份的开始日期和开始日期之间的月数,然后减去此数。
    (@ROUND ("Start Date",-2) - @ROUND ("Start Date",-4))/100
    计算 (20191100 – 20190000)/100 的结果为 11。
  4. 将前面的步骤结合到一个公式 (12+6-11) 中来计算开始日期和结束日期之间的月数 (7)。
    (((@ROUND ("End Date",-4) - @ROUND ("Start Date",-4))/10000*12) + 
    ((@ROUND ("End Date",-2) - @ROUND ("End Date",-4))/100)-
    ((@ROUND ("Start Date",-2) - @ROUND ("Start Date",-4))/100))
使用 @CURRMBR 函数

@CURRMBR 函数可返回当前正在计算的维成员名称,此函数对于确定范围和管理复杂计算特别有用。但是,您必须考虑其性能影响。

在稀疏维上使用 @CURRMBR 函数时不会影响性能,因为块仅对应一个稀疏维成员。但是,在密集维上使用此函数时,性能会降低,因为该函数在块级别而不是单元格级别运行计算。因此,此函数将计算所有密集维成员,即使查询中不存在特定的密集维成员。所以,尽可能少地将此函数用于密集维。

此外,在密集维上使用时,如果与 @CONCATENATE 等其他函数结合使用,@CURRMBR 函数可能会产生意外结果或错误。例如,如果查询中的动态计算成员包含公式 "Actual"->@MEMBER(@CONCATENATE(@NAME (@CURRMBR ("Account")),"_Total")) 且帐户维是稀疏维,则只要查询中的帐户生成有效的大纲成员,查询就不会出现错误。但是,如果帐户维是密集维,即使查询中的帐户生成了有效的大纲成员,查询也会导致以下错误。

执行 [成员名称] 的公式时出错 (第 0 行): 尝试越过函数 [@X] 中的空 @ 成员

出现此错误的原因是 @CURRMBR 函数在块级别进行计算,因此会计算密集块中的所有帐户。但并非块内的所有帐户都会生成有效的大纲成员,从而出现了前面的错误消息。有关 @CURRMBR 函数的详细信息,请参阅 《Oracle Essbase Technical Reference》 中的 " @CURRMBR "。

使用块模式和单元格模式

  • 使用块模式(单元格分组在块中并同时进行计算)通常更快,但必须认真考虑数据相关性。例如,应在单元格模式下计算 SalesYTD = CurMth + PriorMth,以便按照大纲的顺序计算每个月。
  • 在单元格模式下,将按大纲中密集维的顺序计算每个单元格,因此通常会比块模式慢。
  • 使用 @CALCMODE 可手动控制使用块模式还是单元格模式。
  • 使用调试模式应用程序日志可验证计算模式。如果计算是在块模式下执行的,则不会显示任何消息。如果计算是在单元格模式下执行的,则会显示日志消息。

创建块和块大小的建议

为了获得最佳性能,建议块大小介于 8 KB 到 200 KB 之间。为了保持 BSO 块大小最佳,Oracle 建议仅将用于计划和预测的帐户添加到 BSO 多维数据集。如果可能,可通过将所有报告帐户添加到 ASO 多维数据集来使用 ASO 多维数据集进行报告。此外,为了简化块大小,Oracle 建议密集维中的较高级别(即其子代的聚合)都进行动态计算(非存储)或仅作为标签。

通常在执行以下操作时创建块:

  • 数据加载
  • DATACOPY
  • 稀疏计算,例如 AGG or SparseMember = X * X/X;

在以下情况下会触发稀疏计算:

  • 稀疏成员在等号 (=) 左侧。
  • 公式在稀疏计算成员块内;例如,"Budget"("Sales" = "Sales"->"Actual" * 0.95;),假设“方案”是稀疏维而“度量”是密集维。

可使用计算命令 SET CREATEBLOCKONEQSET CREATENONMISSINGBLK 或计算函数 @CREATEBLOCK 创建块。

Oracle 建议谨慎使用这些设置,并在严格的 FIX 语句中使用。进行测试,以确定是否可以通过更改执行的计算类型来避免使用这些语句。

遇到问题时,在使用这些计算命令或函数之前,首先确定此问题是否与块创建有关。可以通过向目标块提交一个零 (0),然后重新运行计算来确定问题是否与块创建相关。

在业务规则开发过程中,测试可能导致块创建问题的规则时,请始终清除并重新加载数据(而不是提交 #missing 或运行 clearblockcleardata 脚本)。

使用 BottomUp 和 TopDown 计算

  • 添加计算函数 @CALCMODE(BOTTOMUP) 或计算命令 SET FRMLBOTTOMUP 以仅计算现有块 (BOTTOMUP) 而不是潜在块 (TOPDOWN)。
  • 由于 TOPDOWN 计算会计算具有成员的所有潜在数据块,因此会删除稀疏维中的任何不相关成员。
  • 使用 BOTTOMUP 对计算进行充分测试,以确保使用 @CALCMODE 时能够正确创建块。
  • 使用 BOTTOMUP 计算时,通过清除数据并重新运行计算来完全测试计算,以确定所有块均已正确创建。
  • 使用调试模式应用程序日志可验证计算模式。如果计算是按 BOTTOMUP 执行的,则不会显示任何消息。如果计算是按 TOPDOWN 执行的,则会显示日志消息。

聚合

  • 稀疏维聚合应进行排序,从创建的块最少的维开始,到创建的块最多的维结束,以尽可能长久地保持尽可能少的块数。
  • 不要让最终用户业务规则聚合整个稀疏维。
  • 仅将报告所需的聚合移动到 ASO 规划类型。
  • 仅聚合规划审批流程所需的数据。

使用 AGG 而不是 CALC DIM 计算命令

  • CALC DIM 会执行所有成员公式。
  • CALC DIM 会聚合密集维或稀疏维。
  • AGG 会根据大纲结构进行聚合。
  • AGG 不执行成员公式。
  • AGG 仅聚合稀疏维。
测试 AGG 和 CALC DIM,因为性能可能因计算中涉及的聚合级别而异。从所有聚合中排除在较高级别具有动态计算的维。仅聚合所需数据。

SET CALCPARALLEL 和 FIXPARALLEL 计算命令的使用

  • 对于可能并发运行规则的多用户应用程序,请在串行模式下运行业务规则。
  • 在批量计算中,仅使用 SET CALCPARALLEL 来处理完全稀疏维聚合。
  • 不建议对小脚本使用并行计算;例如,运行时间小于 20 秒的脚本,因为创建并行计算的开销可能会超过其益处。
  • 始终测试 SET CALCPARALLEL 以确保并行计算是有益的。有时串行计算或并行度较低的计算可以产生较好的结果。
  • 进行测试以确定 FIXPARALLEL 提供的结果是否比 SET CALCPARALLEL 要好。在调试模式下使用 Calculation Manager 检查日志。
  • 使用 SET CALCPARALLELFIXPARALLEL 时,请始终考虑用户并发性。

有关详细信息,请参阅 《Oracle Essbase Technical Reference》 中的 "FIXPARALLEL...ENDFIXPARALLEL"。

启用混合多维数据集对 Planning 中计算的影响

如果您使用常量而非来自其他成员的数据值(例如,对于“二月”,“月中的天数”= 28)在计算中分配值,请检查支持混合多维数据集的 Planning 业务流程中的计算结果。

支持混合多维数据集的 Planning 业务流程中的计算结果可能与不支持混合多维数据集的业务流程中观察到的结果不同。计算结果存在差异的原因可能是:支持混合多维数据集的 Planning 业务流程使用的配置忽略了仅基于常量分配数据值的公式。要解决此问题,请在公式的密集元素上添加 @CreateBlock。当 @CreateBlock 在密集维上时,此添加同时为所有其他密集元素创建块。此外,对每个 IF 语句使用 ELSE 语句,以确保创建了所有必需的块。

有关 Oracle Enterprise Performance Management Cloud 中的 Essbase 用户的信息,请参阅 《Oracle Enterprise Performance Management Cloud 管理员入门》 中的“关于 EPM 云中的 Essbase”。