Fast dynamic named set calculation

时光总嘲笑我的痴心妄想 提交于 2019-12-11 06:23:24

问题


I have a long complex query with a lot of calculations and conditions but the main structure looks like this:

WITH
MEMBER [Id1] AS [Level].[Level1].CurrentMember.Member_Key
MEMBER [Id2] AS [Level].[Level2].CurrentMember.Member_Key
MEMBER [Level].[Level1].[FirstSet] AS NULL
MEMBER [Level].[Level1].[SecondSet] AS NULL
SET [Set 1] AS {some processed set members}
SET [Set 2] AS {some other processed set members}
SET [Common CrossJoin Set] AS [Level].[Level2].Members

MEMBER [Calculated Measure 1] AS
  IIF([Level].[Level].CurrentMember.Member_Key = 'FirstSet',
    SUM(existing [Set 1]),
    IIF([Level].[Level].CurrentMember.Member_Key = 'SecondSet',
      SUM(existing [Set 2]),
      SUM([Measures].[Measure1]) * 15
    )
  )

MEMBER [Calculated Measure 2] AS
IIF([Level].[Level].CurrentMember.Member_Key = 'FirstSet',
  SUM(existing [Set 1]),
  IIF([Level].[Level].CurrentMember.Member_Key = 'SecondSet',
    SUM(existing [Set 2]),
    SUM([Measures].[Measure2]) * 20
  )
)
SELECT 
  { [Id1], [Id2], [Calculated Measure 1], [Calculated Measure 2]} ON COLUMNS,
  { ([Common CrossJoin Set], [Level].[Level1].[FirstSet]),
    ([Common CrossJoin Set], [Level].[Level1].[SecondSet])
  } ON ROWS
FROM [Cube]

So resulted table looks like this:

║ ---------------║ ---------------------------║ Id1 ║ Id2 ║ Measure1 ║ Measure2 ║

║ L2 Member ║ L1.FirstSet Member ║ L2-1 ║ L1-8 ║ 1 ║ 5 ║

║ L2 Member ║ L1.FirstSet Member ║ L2-2 ║ L1-9 ║ 2 ║ 6 ║

║ L2 Member ║ L1.SecondSet Member ║ L2-3 ║ L1-98 ║ 3 ║ 7 ║

║ L2 Member ║ L1.SecondSet Member ║ L2-4 ║ L1-99 ║ 4 ║ 8 ║

The result is correct but the query is very slow (>4sec). My actual query is bigger and contains a lot of such Sets and measures so it seems like the problem is in existing function and overall structure that prevents engine from inner optimizations to be performed.

This kind of solution is wrong and ugly, but how can I rewrite it and get the same result faster?


回答1:


I suspect that the bottleneck is because when you use Iif neither of the logical branches is NULL so you're not getting block mode calculations: this is a better way of using Iif : Iif(someBoolean, X, Null) or Iif(someBoolean, Null, x) but unfortunately in your case you cannot have null in either.

Maybe you could try implementing this type of pattern suggested by Mosha for replacing Iif:

WITH 
MEMBER Measures.[Normalized Cost] AS [Measures].[Internet Standard Product Cost]
CELL CALCULATION ScopeEmulator 
  FOR '([Promotion].[Promotion Type].&[No Discount],measures.[Normalized Cost])' 
  AS [Measures].[Internet Freight Cost]+[Measures].[Internet Standard Product Cost]
MEMBER [Ship Date].[Date].RSum AS Sum([Ship Date].[Date].[Date].MEMBERS), SOLVE_ORDER=10
SELECT 
 [Promotion].[Promotion Type].[Promotion Type].MEMBERS on 0
 ,[Product].[Subcategory].[Subcategory].MEMBERS*[Customer].[State-Province].[State-Province].MEMBERS ON 1
FROM [Adventure Works]
WHERE ([Ship Date].[Date].RSum, Measures.[Normalized Cost])

This is from this blog post about optimizing Iif: http://sqlblog.com/blogs/mosha/archive/2007/01/28/performance-of-iif-function-in-mdx.aspx

So looking at one of your calculations - this one:

MEMBER [Calculated Measure 1] AS
  IIF([Level].[Level].CurrentMember.Member_Key = 'FirstSet',
    SUM(existing [Set 1]),
    IIF([Level].[Level].CurrentMember.Member_Key = 'SecondSet',
      SUM(existing [Set 2]),
      SUM([Measures].[Measure1]) * 15
    )
  )

I think we could initially break it down to this:

MEMBER [Measures].[x] AS SUM(existing [Set 1])
MEMBER [Measures].[y] AS SUM(existing [Set 2])
MEMBER [Measures].[z] AS SUM([Measures].[Measure1]) * 15
MEMBER [Calculated Measure 1] AS
  IIF([Level].[Level].CurrentMember IS [Level].[Level].[Level].[FirstSet],
    [Measures].[x],
    IIF([Level].[Level].CurrentMember IS [Level].[Level].[Level].[SecondSet],
      [Measures].[y],
      [Measures].[z]
    )
  )  

Now trying to apply Mosha's pattern (not something I've tried before so you will need to adjust accordingly)

MEMBER [Measures].[z] AS SUM([Measures].[Measure1]) * 15
    MEMBER [Measures].[y] AS SUM(existing [Set 2])
    MEMBER [Measures].[x] AS SUM(existing [Set 1])
MEMBER [Calculated Measure 1 pre1] AS [Measures].[z]
CELL CALCULATION ScopeEmulator 
  FOR '([Level].[Level].[Level].[SecondSet],[Calculated Measure 1 pre1])' 
  AS [Measures].[y] 
MEMBER [Calculated Measure 1] AS [Calculated Measure 1 pre1]
CELL CALCULATION ScopeEmulator 
  FOR '([Level].[Level].[Level].[FirstSet],[Calculated Measure 1])' 
  AS [Measures].[x]


来源:https://stackoverflow.com/questions/40401652/fast-dynamic-named-set-calculation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!