2

我有一个引用 SQL Server Analysis Services 2008 R2 企业版多维数据集的 MDX 查询,从功能的角度来看,该多维数据集准确而正确地返回了所需的数据。但是,执行此查询需要 5-10 分钟,这对于我们的最终用户在 SSRS 报告中执行此查询是无法接受的。

查询如下:

With Member [Measures].[CurrentPaidAmount] as 
Sum ( 
     Tail(nonempty(descendants([Valuation Date].[DateHierachy].currentmember,4),[Measures].[SaleCount]),1),
[Measures].[CurrentTotalPaidAmt] 
    ) 
Member [Measures].[PreviousPeriodPaidAmount] as 
Sum ( 
     Tail(descendants([Valuation Date].[DateHierachy].currentmember.prevmember,4),1), 
     [Measures].[CurrentTotalPaidAmt] 
     ) 
Member [Measures].[YTDCurrentPaidAmount] as 
([Measures].[CurrentPaidAmount] - [Measures].[PreviousPeriodPaidAmount]) 
select non empty 
    ( {[Valuation Date].[DateHierachy].[Year]}, {[Valuation Date].[Year].children}, 
      {[Valuation Date].[Month].[All]}, {[DimLocation].[State].[All]}, 
      {[DimSeller].[Store].children}, {[DimProduct].[ProductCode].children}, 
      {[DimProgram].[ProgramLine].children ) on rows, 
 [Measures].[YTDCurrentPaidAmount] on columns 
from 
    [CB_Sales]

该基础事实表以累积方式存储 [total paid amount] 度量,即在该月的最后一天,计算自开始时为特定产品支付的总美元。这意味着在每个月的月底,当月的总支付美元被添加到上个月的金额中,以便及时创建自相关产品的所有支付美元的总和。

我的要求是仅计算每一年为每种产品支付的总金额。

考虑以下示例数据集,其中列出了特定产品的当月至今支付的总金额:


12/2010 产品 A:25.00 美元

11/2011 - 产品 A:50.00 美元

12/2011 - 产品 A:100.00 美元

1/2012 - 产品 A:150.00 美元

2/2012 - 产品 A:160.00 美元

2012 年 3 月 - 产品 A:200.00 美元


如果我想获得仅在 2011 日历年为上述产品 A 支付的总美元,我将获得截至 2010 年 12 月为产品 A 支付的总日历(即 25.00 美元)并从总金额中减去该金额截至 2011 年 12 月支付的美元(即 100.00 美元)。

减去 2 个值会产生 75.00 美元的差值:

($100.00 - $25.00) = $75.00

这表明仅在 2011 日历年就为产品 A 支付了 75.00 美元。

话虽如此,回到上面的 MDX 查询,我创建了 2 个计算成员来执行此计算。

会员 (1):

[措施].[CurrentPaidAmount]

此计算的成员根据 [Valuation Date].[DateHierachy].[Year] 属性的当前成员获取为当前日历年记录的最后一个非空总美元支付金额。由于对于当前 2012 日历年,记录总美元的最后一个月是 2012 年 6 月,因此计算出的成员需要足够聪明,以识别日期层次结构中的 [June] 2012 月份成员是支付总额的特定月份美元应该从中取出。

我返回相关日期维度的 [Year] 属性很重要,因为他们希望此成员显示在表格报告中。

因此,我在计算的度量中包含了以下集合,它将根据结果集中返回给客户端的内容获取当前年份值,并向下导航日期层次结构,直到我得到相关日历年内的最后一天具有如下所示的有效总支付金额:

Tail(nonempty(descendants([Valuation Date].[DateHierachy].currentmember,4),[Measures].[SaleCount]),1),

我的理由是,如果用户选择连接报告中的所有年份,那么对于每一年,该特定计算成员将获得相关日历年的最后一个非空总美元支付金额,并允许我从上一年中减去该金额以获得仅在有关日历年内发生的已支付美元总额。

现在,我上面列出的完整 MDX 查询在执行时确实返回了正确的数据。执行需要很长时间,但执行时间超过 5-10 分钟。基础事实表包含 6400 万条记录。

奇怪的是,如果我像这样从第一个计算成员中的集合中删除 nonempty() 子句,则修改后的查询只需 30 秒即可执行:

With Member [Measures].[CurrentPaidAmount] as 
Sum (
      Tail(descendants([Valuation Date].[DateHierachy].currentmember,4),1), [Measures].[CurrentTotalPaidAmt] 
    )

我只能假设 nonempty() 子句阻碍了查询的性能,因为计算成员需要评估日期成员与 [Measures].[SaleCount] 度量的每个交集。

有什么方法可以重写上面的查询以在 30 秒内而不是几分钟内更好、更快、更有效地执行?

我将默认聚合应用于多维数据集,并将其划分为多个多维数据集分区。

我是 MDX 的新手,非常感谢您的建议。

感谢您的时间!

4

3 回答 3

0

我是 MDX 的绝对新手,但在尝试解决我自己在删除 NON EMPTY 子句时的性能问题时遇到了一个潜在的解决方案。您可以尝试在计算成员的基本信息窗格中设置非空行为?问候

卡尔

于 2012-07-19T08:42:34.550 回答
0

如果你混入 EXISTING,你有时会得到对抗 NONEMPTY 的提升:

http://cwebbbi.wordpress.com/2009/03/31/existing-and-nonempty/

他在那里改变

COUNT(NONEMPTY(
NONEMPTY(
EXISTING [Customer].[Customer].[Customer].MEMBERS
, [Measures].[Internet Sales Amount])
, ([Measures].[Internet Sales Amount], [Date].[Calendar].CURRENTMEMBER.PREVMEMBER))
)

COUNT(EXISTING  
NONEMPTY(
NONEMPTY(
[Customer].[Customer].[Customer].MEMBERS
, [Measures].[Internet Sales Amount])
, ([Measures].[Internet Sales Amount], [Date].[Calendar].CURRENTMEMBER.PREVMEMBER))
)

速度提高八倍。

您在日期维度上遇到这种情况似乎很奇怪 - 至少与其他维度(例如客户或产品)相比,通常没有很多日期。您的日期维度有多长,您是否不必要地进入未来或过去?

您可以查看基于使用情况的优化,设置 SSAS 服务器属性,将 MDX 调用记录到您指定的数据库,然后运行向导以基于此创建一组聚合。然后,您将聚合分配给分区,如果我没记错的话,“进程索引”...

http://www.sqlservercentral.com/articles/Analysis+Services+(SSAS)/usagebasedoptimizationinssas2005/2419/

于 2012-07-11T13:44:54.163 回答
0

如果您的事实表可以存储非累积支付金额,您将直接拥有[Measures].[YTDCurrentPaidAmount],并且将避免计算[Measures].[CurrentPaidAmount]and [Measures].[PreviousPeriodPaidAmount]

于 2012-07-11T06:33:15.297 回答