使用可配置计算时,请遵循以下最佳做法。
计算概念
以下是创建计算的基本概念:
数据块
基本脚本格式
自下而上与自上而下计算
块与单元格模式
数据块
下图显示了示例应用程序中的数据块。
密集维的存储成员构成一个数据块。上述示例应用程序的块大小为 2(Sales 和 Cash)x 8 字节 = 16 字节。
稀疏维成员的唯一组合构成索引并指向数据块。在上述示例应用程序中,共有 2(Actual、Budget)x 2(FY17、FY18)x 2(Jan、Feb)= 8 个索引。
在 Essbase 块存储选项 (Block Storage Option, BSO) 数据库中,一个块构成一个密集维的存储成员。在 Financial Consolidation and Close 中,默认情况下,“帐户”是唯一的密集维。
在此示例中,Account(帐户)为密集维,具有 1977 个存储成员。这表示单个 BSO 数据库合并的块中有 1977 个单元格,每个单元格代表一个帐户成员。
块大小(以字节为单位)将为:
块大小(字节)= 帐户中的存储成员数 * 8
块大小(字节)= 1977 * 8 = 15,816 字节
注意:要查看数据库属性,请在 Calculation Manager 中,依次选择操作和数据库属性。
创建数据块的最佳做法
在执行向数据单元格写入的可配置计算时,必须存在数据块,才能向数据库写入数据。
数据块是存储的稀疏和密集维成员的组合。
对于存储的稀疏维的每种组合,都会创建单独的数据块。一个密集维中的成员相当于一个块。
当您创建可配置的计算时,您可能需要创建额外的块以存储计算结果并解决缺少数据的问题。
您可以启用“自动创建块”选项,让系统自动创建缺少的块。请参阅“支持自动为可配置计算创建块”。
如果您在可配置计算中使用自下而上处理,应手动创建数据块或确保数据块已存在。
可使用以下方法之一手动创建数据块:
在数据加载过程中分配数据。例如,向单个密集成员交叉点写入 "0"(零),然后写入 "#missing" 以在创建块之后清除 "0"。
使用 Essbase DATACOPY 命令:在此命令中,可以将来自源的所有块复制到目标,包括缺少的单元格。但是,此方法可能会创建不必要的块,从而降低合并过程的速度。
何时使用自动创建块
提供的“自动创建块”设置用于在可配置计算期间创建缺少的块。
此设置对性能影响很大,因为它使用潜在块算法在整个数据库中搜索是否存在块,并在不存在的情况下相应地创建缺少的块。
仅当完全确定其他块创建技术都不适用时,才使用此设置。
@CALCMODE(BOTTOMUP) 函数(如果在插入点中使用)和“自动创建块”互斥。
为 @SHIFT 和 @PRIOR 函数创建目标数据块
在计算脚本中使用 @SHIFT 或 @PRIOR 函数时,必须存在目标数据块才能运行计算。目标数据块必须包含在其他计算或数据加载中,或者必须使用 @CREATEBLOCK 函数来创建。
用例示例:
数据存在于 Actual、FY16、P12、ML_HFM 中。正在从 Oracle Hyperion Financial Management 拉取数据,尚未加载到 Actual、FY16、P1、ML_HFM 中。必须从上一年的 P12 期间检索数据,并且应在 Actual、FY17、P1、ML_HFM_Calc 中反映出冲销分录。
计算脚本如下所示:
未推送任何日记帐(P13 中的 "FCCS_Journal Input"。代码应采用以下路径,并使用 "ML_HFM_Calc" 作为稀疏成员锚点:
@SHIFT("P12"->"ML_HFM", -1, @CHILDREN("Years"));
但是,此函数返回 #MISSING。
解决方法 1:
解决方法 2:
ClearEmptyBlocks 规则的准则
ClearEmptyBlocks 业务规则可帮助清理合并多维数据集的任何空数据块。空数据块可能是由于以下原因而生成的:
生成空块的按需规则执行。例如,使用 @CREATEBLOCK 函数,然后生成的空数据块可能永远得不到使用。
可能出现块泄漏的插入点代码(例如 FCCS_20),这可能来自 TOPDOWN 计算,分配 #MISSING;使用稀疏锚点,而不是使用 @CALCMODE(BOTTOM UP)
Financial Consolidation and Close 系统计算
运行 ClearEmptyBlocks 规则的建议做法
脚本处于开发阶段时,最佳做法是在完成任何按需规则/插入点测试后运行该规则。ClearEmptyBlocks 规则可帮助您在开发环境下收集计算前后的块统计信息。
在生产阶段,在完成给定年份的全年合并之后执行该规则。
EPM Automate 脚本可以安排在下班后(每周末)运行:
call epmautomate runbusinessrule ClearEmptyBlocks Scenario ="<Scenario>" Year = "<Particular Year>" Period = "ILv10Descendants(YearTotal)" call epmautomate restructurecube Consol
注意:此活动的计划执行时间必须与日常维护周期至少间隔三至四小时。
基本脚本格式
下图显示了示例计算脚本格式。
编写可配置计算
下图显示了“合并过程本地货币”选项卡上的“可配置计算”规则。
下图显示了“合并过程本地货币”选项卡上的相应“可配置计算”规则。
可配置计算有助于执行涉及三类数据的自定义计算:
未转换的数据:实体货币 +(FCCS_Entity Input 或 FCCS_Entity Consolidation)
转换的数据:父代货币 +(FCCS_Entity Input 或 FCCS_Entity Consolidation)
抵消的数据:父代货币 + FCCS_Elimination
了解货币和合并组合非常重要,这有助于在正确的“可配置计算规则”模板(也称为“插入点”)中编写可配置计算。
例如,当且仅当 FCCS 默认转换和外汇计算已经处理了 FCCS_30 中需要特别注意的数据时,才应使用 FCCS_30_After Opening Balance Carry Forward_Translated。
编写可配置计算示例
下面是一个块创建问题的示例以及解决同一计算的不同方法。
用例:
在两个帐户中添加值:Warehouse_Stock 和 Showroom_Stock 加载到 FCCS_Managed Data、FCCS_Mvmts_NetIncome、FCCS_Local GAAP 和 No Product
将计算结果存储到 FCCS_Other Data、FCCS_Mvmts_NetIncome、FCCS_Local GAAP 和 No Product 的 Inventory_Stock 帐户中
使用 FCCS_10 可配置计算
方法 1:不使用成员块(锚点)
1. FIX ("FCCS_Entity Input", "Entity Currency") 2. FIX ("FCCS_Other Data", "FCCS_Mvmts_NetIncome", "FCCS_No Intercompany", "No Product", "FCCS_Local GAAP") 3. " Inventory_Stock " = "FCCS_Managed Data"->" Warehouse_Stock " + "FCCS_Managed Data"-> "Showroom_Stock "; 4. ENDFIX 5. ENDFIX
此方法的劣势:
考虑到 Inventory_Stock
是左侧的帐户,此为密集计算。尽管计算编写无误,但如果 FCCS_Other Data
和关联的其他 FIX 成员不存在任何先前的块来保存结果,则您将看不到计算结果。
无法强制执行条件计算限制,例如 IF..ELSE..ENDIF。
解决方法是手动将零数据块引入上述交叉点。
方法 2:使用密集成员块(锚点)
1. FIX ("FCCS_Entity Input", "Entity Currency") 2. FIX ("FCCS_Other Data", "FCCS_Mvmts_NetIncome", "FCCS_No Intercompany", "FCCS_No Intercompany", "FCCS_Local GAAP") 3. " Inventory_Stock "( 4. "FCCS_Managed Data"->" Warehouse_Stock " + "FCCS_Managed Data"->" Showroom_Stock "; 5. ) 6. ENDFIX 7. ENDFIX
此方法的劣势:
此为密集计算,因为成员块 Inventory_Stock
是一个帐户。尽管计算编写无误,但如果 FCCS_Other Data
和关联的其他 FIX 成员不存在任何先前的块,则您将看不到计算结果。
解决方法是手动将零数据块引入上述交叉点。
方法 3:使用稀疏成员块(锚点)
1. FIX ("FCCS_Entity Input", "Entity Currency") 2. FIX ("FCCS_Mvmts_NetIncome", "FCCS_No Intercompany", "No Product", "FCCS_Local GAAP") 3. "FCCS_Other Data" ( 4. " Inventory_Stock " = "FCCS_Managed Data"->" Warehouse_Stock " + "FCCS_Managed Data"-> "Showroom_Stock "; 5. ) 6. ENDFIX 7. ENDFIX
此方法的优势:
此为稀疏计算,因为成员块 FCCS_Other Data
是数据源,其为稀疏维。计算会产生块。
此方法的劣势:
由于使用了跨维运算符,成员块计算自上而下运行。
方法 4:使用稀疏成员块和自下而上计算
1. FIX ("FCCS_Entity Input", "Entity Currency") 2. FIX ( "FCCS_Mvmts_NetIncome", "FCCS_No Intercompany", "No Product", "FCCS_Local GAAP") 3. "FCCS_Managed Data"(@CALCMODE(BOTTOMUP); 4. "FCCS_Other Data"-> "Inventory_Stock " = " Warehouse_Stock " + " Showroom_Stock "; 5. ) 6. ENDFIX 7. ENDFIX
此方法的优势:
此为稀疏计算,因为成员块 FCCS_Managed Data
是数据源,即稀疏维。
成员块计算自下而上运行。
FCCS_Managed Data
是此计算的源。当且仅当数据块存在于源中时,才在 FCCS_Other Data
中创建结果块。
计算的右侧不需要跨维运算符。
需要将计算明确指定为“自下而上”,因为此指定的左侧存在一个跨维运算符。
块与单元格模式计算
块模式:(默认模式)在此计算模式下,Essbase 对块内的单元格进行分组,并同时计算每个组中的单元格。
块计算模式速度快,但需要仔细考虑块内的数据相关性,以确保生成的数据准确无误。
单元格模式:在此计算模式下,Essbase 将根据大纲的计算顺序依次计算每个单元格。
显然,单元格计算模式速度较慢。但是,此模式可以确保在涉及数据相关性的情况下结果准确。
编译公式时,Essbase 会在应用程序日志文件中输出一条消息说明该公式的执行模式,此消息如下所示:
Formula on member Profit % will be executed in CELL and TOPDOWN mode.
Essbase 在计算公式时使用块模式,除非使用以下函数:
@ANCEST
@CURRMBR
@ISMBR on a dense member
@MDANCESTVAL
@MDPARENTVAL
@MDSHIFT
@NEXT
@PARENT
@PARENTVAL
@PRIOR
@SANCESTVAL
@SPARENTVAL
@SHIFT
@XWRITE
要手动引入块模式,请使用 @CALCMODE(BLOCK)。确保密集块内的数据不相关。
块模式示例
根据月份执行以下计算:
Sales Synergies
是 Returns and Allowances
子代的总和Sales Synergies
是 Returns and Allowances
子代的总和乘以 20%Sales Synergies
是 Returns and Allowances
子代的总和乘以 10%块模式
1. FIX ("FCCS_Entity Input", "Entity Currency") 2. FIX ("Sales Synergies", "FCCS_No Intercompany", "FCCS_Managed Data", "No Product", "FCCS_Local GAAP") 3. "FCCS_Mvmts_NetIncome" ( 4. IF (@ISMBR("Jan")) 5. @SUM(@Children("Returns and Allowances")); 6. ELSEIF (@ISMBR("Feb")) 7. @SUM(@Children("Returns and Allowances")) * 0.2; 8. ELSE 9. @SUM(@Children("Returns and Allowances")) * 0.1; 10. ENDIF 11. ) 12. ENDFIX 13. ENDFIX
单元模式与引入的块模式
根据月份执行以下计算:
一月 - Sales Synergies
是 Returns and Allowances
子代的总和
二月 - Sales Synergies
是 Returns and Allowances
子代的总和乘以 20%
其余月份 - Sales Synergies
是 Returns and Allowances
子代的总和加上前一期间的 Sales Synergies
,整个结果再乘以 10%。
单元格模式
1. FIX ("FCCS_Entity Input", "Entity Currency") 2. FIX ("Sales Synergies", "FCCS_No Intercompany", "FCCS_Managed Data", "No Product", "FCCS_Local GAAP") 3. "FCCS_Mvmts_NetIncome" ( 4. IF (@ISMBR("Jan")) 5. @SUM(@Children("Returns and Allowances")); 6. ELSEIF (@ISMBR("Feb")) 7. @SUM(@Children("Returns and Allowances")) * 0.2; 8. ELSE 9. (@SUM(@Children("Returns and Allowances")) + @PRIOR("Sales Synergies")) * 0.1; 10. ENDIF 11. ) 12. ENDFIX 13. ENDFIX
块模式
1. FIX ("FCCS_Entity Input", "Entity Currency") 2. FIX ("Sales Synergies", "FCCS_No Intercompany", "FCCS_Managed Data", "No Product", "FCCS_Local GAAP") 3. "FCCS_Mvmts_NetIncome" (@CALCMODE(BLOCK); 4. IF (@ISMBR("Jan")) 5. @SUM(@Children("Returns and Allowances")); 6. ELSEIF (@ISMBR("Feb")) 7. @SUM(@Children("Returns and Allowances")) * 0.2; 8. ELSE 9. (@SUM(@Children("Returns and Allowances")) + @PRIOR("Sales Synergies")) * 0.1; 10. ENDIF 11. ) 12. ENDFIX 13. ENDFIX
客户 A 用例
根据日记帐调整,将从 FDMEE 加载的“损益表”帐户的管理数据重新分类到另一个计算数据源成员
性能低下:全年 180 分钟
客户 A - 脚本示例
客户 A - 脚本改进
在帐户密集维上使用 @REMOVE 删除帐户,而不是使用 @ISMBR 检查
自下而上处理
使用布尔 @ISLEV,而不是 @LEV 和 @CURRMEMBER
性能提高 90%
客户 B 用例
目标 - 将数据从某些源实体移动到目标实体
数据未得到计算
性能低下 - 3.5 小时
客户 B - 脚本示例
客户 B - 脚本改进
使用“复制”创建目标块
计算仍采用自上而下
仅在一个目标自定义维成员上执行计算
使用 @LIKE 将脚本设置为常规
时间从 3.5 小时减少到几分钟
客户 C 用例
根据用户界面输入的 FCCS_Closing_Balance_Input 对移动进行重新分类
性能低下 - 15 分钟
客户 C - 脚本示例(续)
客户 C - 脚本改进
从 FIX 中删除受限制的成员
自下而上处理
检查边缘用例
首先检查常见用例。
性能提高 40%
客户 D 用例
对从 Hyperion Financial Management 数据源 ML_HFM 中提取的数据进行重新分类,并将其存储在 ML_HFM_Calc 数据源成员中
性能低下 – 单个期间 24 小时
数据未关联在一起,因为未按预期创建块
客户 D - 脚本示例
客户 D - 脚本改进
在帐户密集维上使用 @REMOVE 删除帐户,而不是使用 @ISMBR 检查
自下而上处理
使用布尔 @ISLEV,而不是 @LEV 和 @CURRMEMBER
性能提高 90%
客户 E 用例
合并方法在当前期间发生了更改,希望删除较早期间的所有累计 CTA 和抵消处理
性能低下 - 90 分钟
客户 E - 脚本改进
在目标中使用 Data_Input 以避免有关写入 FCCS_Intercompany_Eliminations 的验证错误
自下而上遍历具有期末余额输入的 ICP 成员
时间从 90 分钟减少到 11 分钟
最佳做法汇总
自下而上处理
在帐户密集维上使用 @REMOVE 删除帐户,而不是使用 @ISMBR 检查
使用布尔 @ISLEV,而不是 @LEV 和 @CURRMBR
从 FIX 中删除受限制的成员
如果锚点方法不适用,则使用“复制”创建目标块
仅在一个目标自定义维成员上执行计算
使用 @LIKE 将脚本设置为常规
避免自动创建块
检查边缘用例
首先检查常见用例。
性能最佳做法
多次遍历 Essbase
每次在规则中使用 FIX 语句时,每个 FIX 都将触发一次单独数据库遍历。出于性能原因的考虑,最好不要包含过多的单独 FIX 语句,以避免多次遍历 Essbase。
示例 - 多次遍历 Essbase
FIX("Entity Currency", "FCCS_Entity Input", …..) FIX("FCCS_Data Input", … ) //Calculations; ENDFIX FIX("FCCS_Other Data", … ) //Calculations; ENDFIX ENDFIX
示例:建议的更改,以避免使用 IF...ENDIF 进行多次遍历
FIX("Entity Currency", ...) FIX( @List("FCCS_Data Input", "FCCS_Other Data"), … ) "FCCS_Entity Input"( @CALCMODE(BOTTOMUP); IF(@ISMBR("FCCS_Data Input") //Calculations for "FCCS_Data Input"; ELSE //Calculations "FCCS_Other Data"; ENDIF ) ENDFIX ENDFIX
示例:建议的更改,以避免使用成员块进行多次遍历
FIX("Entity Currency", ...) FIX( @List("FCCS_Data Input", "FCCS_Other Data"), … ) "FCCS_Entity Input"( @CALCMODE(BOTTOMUP); IF(@ISMBR("FCCS_Data Input") //Calculations for "FCCS_Data Input"; ELSE //Calculations "FCCS_Other Data"; ENDIF ) ENDFIX ENDFIX
示例:导致多次遍历 Essbase 的多个单独的嵌套 FIX 语句
FIX("FCCS_Elimination") FIX("No Movement") Fix(@Relative("ICP_Category",0)) "Custom_Elimination" ( "InterSales"="Other_InterAcct"->"FCCS_Intercompany Eliminations"; ) ENDFIX /*Intercompany*/ ENDFIX /*Movement*/ ENDFIX /*Consolidation*/
示例:重写以避免多次遍历
FIX ("FCCS_Elimination",@Relative("ICP_Category A",0), "No Movement") "Custom_Elimination" ( @CALCMODE(BOTTOMUP); "640102" = "WA_Intercompany Account"->"FCCS_Intercompany Eliminations"; ) ENDFIX
写入受限制的成员
在本示例中,假如您希望将 "FCCS_Intercompany Eliminations" > "FCCS_Eliminations" > "Mvmts_NewBusiness" 重新分类为 "Data Input" > "FCCS_Eliminations" > "Mvmts Reclass"。
然而,由于 "FCCS_Intercompany Eliminations" 是数据源维的受限制成员,如果您尝试对该成员使用 FIX,系统将返回错误。
您可以尝试写入以下语句,这会强制系统使用自上而下处理。
示例:使用自上而下的处理功能处理受限制的成员
FIX("Data Input", … ) "FCCS_Elimination" ( "Mvmts_Reclass" = -1 * "FCCS_Intercompany Eliminations"->"Mvmts_NewBusiness" ; ) ENDFIX
示例:重写使用自下而上处理的语句
FIX("FCCS_IntercomanyEliminations", "Mvmts_NewBusiness", … ) "FCCS_Elimination" ( @CALCMODE(BOTTOMUP); "Mvmts_Reclass"->"Data Input" = -1 * "Mvmts_NewBusiness" ; ) ENDFIX
请注意,在本示例中,"FCCS_Intercompany Eliminations" 上有 FIX,但在成员块中使用 "Data Input" 将其覆盖,且系统不会在验证期间返回错误。
在期末余额输入中输入数据并基于 UDA 计算移动
在本例中,假设要将期末余额输入移到特定的移动成员中。您可以编写包含以下要求的自定义计算:
对稀疏维成员组合一起使用 FIX,以实现自下而上处理。自下而上处理与块相关,而稀疏维定义了块。
最好通过对 UDA 帐户使用 FIX 来一起处理用户定义的属性 (User-defined attribute, UDA),以执行相同的计算。
下面的示例假设指定的全部 UDA 都是在资产/负债/权益帐户类型上定义。
对相对于 FCCS_Net Income 的零级帐户维成员使用 FIX
使用布尔函数,而不使用 @LEV 来计算成员的级别,以改进性能
使用布尔函数 @ISDESC 检查成员是否为后代。它将始终为叶成员。
示例:在期末余额输入中输入数据并基于 UDA 计算移动
使用 IF 条件的最佳方式
下面是您使用 IF 写入条件语句时的常见示例。在本示例中,您想在一月份执行某个特定流程,但在其他月份执行其他操作。如果计算按如下写入,系统将所有期间经历 12 次检查,但一月份除外,因为它始终首先检查一月份,然后转到 ELSE 子句。
示例:IF 语句
FIX ("Entity Currency", "FCCS_Entity Input" … ) "Mvmt_Increase01" ( @CALCMODE(BOTTOMUP); IF(@ISMBR("Jan")) "FCCS_ClosingBalance_Input" - @PRIOR("FCCS_ClosingBalance_Input"-> "Dec", 1, @RELATIVE("Years", 0)); ELSE "FCCS_ClosingBalance_Input" - "FCCS_TotalOpeningBalance"; ENDIF ) ENDFIX
示例:使用 NOT IF 重写
您可以重新写入 IF 语句,使 12 个期间中的 11 个期间得以使用 IF 子句执行,然后从条件分支退出。仅一月份在 ELSE 子句中执行一次。
FIX ("Entity Currency", "FCCS_Entity Input", …) "FCCS_ClosingBalance_Input"(@CALCMODE(BOTTOMUP); IF (NOT @ISMBR("Jan")) "Mvmt_Increase01" = "FCCS_ClosingBalance_Input" - "FCCS_TotalOpeningBalance"; ELSE IF(NOT @ISMBR(@MEMBERAT(@CHILDREN("Years"),1))) "Mvmt_Increase01" = "FCCS_ClosingBalance_Input" - "FCCS_ClosingBalance_Input"->"Dec"-> @MEMBER(@PREVSIBLING(@CURRMBR("Years"))); ENDIF; ENDIF; ) ENDFIX
对扩展维度使用顶级自定义成员系统计算选项
对于用户定义的自定义维,服务管理员可以选择使用自定义维的顶级成员(而不是所有的 0 级成员)来处理系统计算,以加快执行速度。您可以选择要为其应用该选项的特定自定义维。请参阅“系统计算”。
如果使用的是扩展维度环境,为了确保使用自定义顶级成员不会减慢执行速度,可以在基于 "Entity Input" 和 "Entity Currency" 数据的合并的开头 "NoCustomX" 处创建一个空白块,并使用该块执行所有计算。例如,如果 Product 自定义维中有 1000 个自定义成员,则可以创建一个 @"No Product" 块,对 "No Product" 使用 FIX,并使用自下而上处理。之后,系统将不需要遍历 Product 维的所有 1000 个成员,您可以使用 "Total Product" 来获取合计值,从而改进总体性能。
以下是计算脚本示例:
使用自下而上处理计算 FCCS_10 成员块
使用 @CALCMODE(BOTTOMUP) 并合并成员块计算。
将多个 FIX...ENDFIX 中的计算合并到单个 FIX...ENDFIX 中,但前提是各个计算中的 FIX 成员相同。
如果 FIX 只是单个计算,请避免在 FIX 内使用 FIX。
以下示例显示如何运行使用自上而下处理的计算,随后显示的是一个修改后使用自下而上处理的示例,它在右侧改进了查询处理。
示例:运行使用自上而下处理的 FCCS_20 C1_Validation
示例:运行使用自下而上处理的 FCCS_20 C1_Validation
计算相关性
当在可配置计算(插入点)和按需规则中进行计算时,应避免实体之间存在相关性。如果尝试在计算中引用实体 A 的值,但实体 A 尚未计算,则实体 A 将不具有值。
例如,如果您尝试将数据从 "Entity A" > "ICP_B" > "Entity Currency"(源)重新分类到 "Entity B" > "ICP_A" > "Entity Currency"(目标),实体 A(源)中的数据可能不可用,因为它可能尚未计算,而是正在同时计算实体 A 和实体 B。
在这种情况下,重新分类应首先计算实体 A,然后计算从属实体 B。