Быстрый динамический расчет именованных множеств
У меня длинный сложный запрос с большим количеством вычислений и условий, но основная структура выглядит так:
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]
Итак, приведенная таблица выглядит так:
║ --------------- ║ --------------------------- ║ Id1 ║ Id2 ║ Measure1 ║ Мера2 ║
║ Член L2 ║ Член L1.FirstSet ║ L2-1 ║ L1-8 ║ 1 ║ 5 ║
║ Член L2 ║ Член L1.FirstSet ║ L2-2 ║ L1-9 ║ 2 ║ 6 ║
║ Член L2 ║ Член L1.SecondSet ║ L2-3 ║ L1-98 ║ 3 ║ 7 ║
║ Член L2 ║ Член L1.SecondSet ║ L2-4 ║ L1-99 ║ 4 ║ 8 ║
Результат правильный, но запрос очень медленный (>4 с). Мой фактический запрос больше и содержит много таких наборов и мер, поэтому кажется, что проблема заключается в существующей функции и общей структуре, которая препятствует выполнению движком внутренних оптимизаций.
Такое решение неверно и уродливо, но как мне переписать его и получить тот же результат быстрее?
1 ответ
Я подозреваю, что узкое место, потому что, когда вы используете Iif
ни одна из логических ветвей не является NULL
так что вы не получаете вычисления в блочном режиме: это лучший способ использования Iif
: Iif(someBoolean, X, Null)
или же Iif(someBoolean, Null, x)
но, к сожалению, в вашем случае вы не можете иметь значение null.
Может быть, вы могли бы попробовать реализовать этот тип шаблона, предложенный Mosha для замены 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])
Это из этого поста об оптимизации Iif
: http://sqlblog.com/blogs/mosha/archive/2007/01/28/performance-of-iif-function-in-mdx.aspx
Итак, глядя на один из ваших расчетов - этот:
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 [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]
)
)
Теперь пытаюсь применить паттерн Моши (не то, что я пробовал раньше, так что вам нужно будет соответственно настроить)
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]