Пользовательские вычисления в кубах Analysis Services  Алексей Шуленин Microsoft
Введение <ul><li>С Вашего позволения я не буду сегодня рассказывать, что такое  OLAP  и для чего он нужен </li></ul><ul><l...
Стандартные меры <ul><li>Как Вы знаете... </li></ul><ul><li>Ячейка, состоящая из нескольких записей таблицы фактов, по умо...
Важное замечание <ul><li>Сказанное не означает, что вычисляются  все  возможные агрегаты </li></ul><ul><ul><li>Их полное ч...
Мера  DISTINCT COUNT <ul><li>Работает только по числовым полям </li></ul><ul><ul><li>В старой документации не отражено </l...
Пример <ul><li>Анализируем журнал  ISA   Server </li></ul><ul><ul><li>Что и когда посещали пользователи </li></ul></ul><ul...
Пример <ul><li>Как следствие, увеличивается время процессинга, снижается масштабируемость </li></ul><ul><ul><li>Весь куб т...
Как посмотреть коллекцию агрегатов <ul><li>DSO.ServerClass olap_server = new DSO.ServerClass(); </li></ul><ul><li>olap_ser...
Точнее – это множества агрегатов <ul><li>В  ROLAP  они видны как  SELECT ы  c GROUP BY  по уровням </li></ul><ul><li>1142 ...
Структура таблицы агрегатов Имя раздела Имя куба Мера, агрегированная в соотв. с ее ф-цией GROUP BY  по членам выбр. уровня
Вопрос на понимание <ul><li>Почему по региону она суммировала так: </li></ul><ul><li>INSERT INTO Продажи_Продажи_03 (Count...
Ответ <ul><li>Найдите 1 существенное отличие: </li></ul><ul><li>Если ключи на протяжении уровня неуникальны  </li></ul><ul...
Последовательность расчета <ul><li>Сначала Analysis Service попробовала создать под агрегаты индексированные представления...
Задание принудительной агрегации в измерении <ul><li>При помощи св-ва  AggregationUsage  интерфейса  Dimension </li></ul><...
Задание принудительной агрегации в уровне <ul><li>При помощи св-ва  EnableAggregations  интерфейса  Level </li></ul><ul><l...
Последовательность выполнения многомерного запроса <ul><li>Посмотреть, может быть, результат уже содержится в кэше на данн...
Calculated Members <ul><li>Традиционно ассоциируются с вычисляемыми мерами </li></ul>
Calculated Members <ul><li>На самом деле может относиться к любому измерению </li></ul><ul><ul><li>Не обязательно  Measure...
Пример <ul><li>Вот измерение «Время» </li></ul>Обратите внимание, что уровень «день» не показан -  Calc Members  не могут ...
Пример <ul><li>Получили еще один «день» в июле 1996 г. </li></ul>
Отличие  calc member  от  member property <ul><li>Member property </li></ul><ul><ul><li>Не увеличивает (хотя бы фиктивно) ...
Создание  calc member <ul><li>Масштаба запроса </li></ul><ul><ul><li>WITH MEMBER … AS ‘MDX- выражение ’ </li></ul></ul><ul...
Создание  calc member ... DSO.CubeClass olap_cube = (DSO.CubeClass) olap_db.Cubes.Item(&quot;Продажи&quot;); string CalcMe...
Multicolumn measures <ul><li>Не обязательно прибегать к  calc members , если агрегат задействует несколько колонок таблицы...
Дополнительные свойства  Calculated Members  по сравнению с мерами <ul><li>FORMAT_STRING, FORE_COLOR, BACK_COLOR, FONT_NAM...
Более сложный пример <ul><li>Если в целом по региону рост нормальный, но внутри есть потомки с отрицательным ростом, краси...
Custom Rollup Formula <ul><li>Отменяет действие агрегатной функции меры и агрегирует детей по данной иерархии в соответств...
Custom Rollup Formula <ul><li>Применяется ко всем членам уровня </li></ul><ul><ul><li>Квартал - > Q1, Q2, Q3, Q4 </li></ul...
Unary Operators <ul><li>С какими знаками члены агрегируются в своего родителя </li></ul><ul><li>В реляц.табл. соотв.поле, ...
Unary Operators <ul><li>Типичный пример измерения – счета </li></ul><ul><ul><li>+ - активы, - - пассивы,  ~ -  внебалансов...
Custom Member <ul><li>Идея – аналогично  Unary Operators,  функционал – шире </li></ul><ul><li>Вместо унарного оператора –...
Calculated Cells <ul><li>MDX- формула, применяемая к более общим областям куба </li></ul><ul><li>Calculation Subcube  зада...
Calculated Cells <ul><li>Calculation Condition  позволяет дополнительно оговорить диапазон вычислений </li></ul><ul><ul><l...
Пример <ul><li>Применим формулу, аналогичную рассмотренной в  Custom Rollup  только к  </li></ul><ul><ul><li>Продажам в шт...
Пример <ul><li>Видим, что все работает: </li></ul><ul><li>В 1997 г. и в 1-м и 2-м кварталах по мере  Unit Sales  сидит дей...
Взаимодействие  пользовательских вычислений <ul><li>Что происходит, когда в одной ячейке сталкиваются </li></ul><ul><ul><l...
Понятие  SOLVE ORDER <ul><li>Пример </li></ul><ul><ul><li>CurrentMember  везде можно опустить – просто, чтобы было понятно...
Понятие  SOLVE ORDER <ul><li>Побеждает 2-я формула </li></ul><ul><li>Побеждает 1-я формула </li></ul>with member Measures....
Понятие  SOLVE ORDER <ul><li>Solve Order  можно видеть и менять только для  Calculated Members  и  Calculated Cells </li><...
Однотипные вычисления по разным осям <ul><li>Т.е. если  Solve Order  одинаковый </li></ul><ul><li>Выигрывает последняя ось...
Понятие  CALCULATION PASS <ul><li>Пример 1 </li></ul><ul><ul><li>Сделать область вычисляемых ячеек, в которой значение каж...
Понятие  CALCULATION PASS <ul><li>Пример 2 </li></ul><ul><ul><li>Измерения  Parent-Child  с опцией  Non-leaf data hidden <...
Номер прохода <ul><li>Итак, имеем ту же вводную, что и для  SOLVE ORDER –  несколько формул на одну ячейку </li></ul><ul><...
Пример <ul><li>select DrilldownLevel({Time.[1997]}) on rows, {Customers.[All Customers]} on columns from Sales where Measu...
Пример <ul><li>Теперь слегка изменим пример </li></ul><ul><ul><li>with cell calculation Calc_Q3 for '({Measures.[Store Sal...
Оценка и вычисление <ul><li>Вопрос </li></ul><ul><ul><li>Почему поменялась сумма в 1997? </li></ul></ul><ul><ul><li>Ведь р...
Пример <ul><li>with cell calculation Test for '({Measures.[Sales Count]}, {Time.[1997].Q1}, {Store.USA.WA.Seattle}, {Produ...
Что происходит <ul><li>Оценка </li></ul><ul><li>Вычисление </li></ul>Шаг 4 Шаг 5 Шаг 3 Шаг 0 1 Q1 Seattle 2 * Q1 Seattle 2...
Вопросы?
 
Upcoming SlideShare
Loading in …5
×

User Aggs In As

658 views
531 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
658
On SlideShare
0
From Embeds
0
Number of Embeds
34
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

User Aggs In As

  1. 1. Пользовательские вычисления в кубах Analysis Services Алексей Шуленин Microsoft
  2. 2. Введение <ul><li>С Вашего позволения я не буду сегодня рассказывать, что такое OLAP и для чего он нужен </li></ul><ul><li>Давайте сразу перейдем к делу </li></ul>
  3. 3. Стандартные меры <ul><li>Как Вы знаете... </li></ul><ul><li>Ячейка, состоящая из нескольких записей таблицы фактов, по умолч. агрегируется одной из след.ф-ций </li></ul><ul><ul><li>Sum </li></ul></ul><ul><ul><li>Count </li></ul></ul><ul><ul><li>Min </li></ul></ul><ul><ul><li>Max </li></ul></ul><ul><ul><li>Distinct Count </li></ul></ul><ul><li>В отличие от пользовательских агрегатов они предвычислены и хранятся в кубе, а не считаются по мере надобности </li></ul>
  4. 4. Важное замечание <ul><li>Сказанное не означает, что вычисляются все возможные агрегаты </li></ul><ul><ul><li>Их полное число ~ е n-1 , где n – размерность куба </li></ul></ul><ul><ul><ul><li>Доказать самим </li></ul></ul></ul><ul><ul><li>Поэтому диск быстро кончится </li></ul></ul><ul><li>На стадии проектирования куба определяются (но не считаются) нужные агрегаты </li></ul><ul><ul><li>Design Storage Wizard пытается соблюсти баланс между размером и производительностью </li></ul></ul><ul><ul><li>Эмпирика – в первую очередь те, от к-х за минимальное число операций можно посчитать остальные </li></ul></ul><ul><ul><li>Потом мн-во агрегатов корректируется на основе типовой нагрузки – Usage-Based Optimization </li></ul></ul><ul><ul><ul><li>Примерно, как ITW </li></ul></ul></ul>
  5. 5. Мера DISTINCT COUNT <ul><li>Работает только по числовым полям </li></ul><ul><ul><li>В старой документации не отражено </li></ul></ul><ul><li>Более &quot;тяжелый&quot; случай по сравнению с остальными </li></ul><ul><li>Как мы знаем, Analysis Service при создании куба считает не все агрегаты </li></ul><ul><ul><li>Остальные могут досчитываться в ходе выполнения запроса на основе известных </li></ul></ul><ul><ul><li>Для аддитивных мер не составляет труда посчитать агрегат, напр., уровня года, если известны агрегаты уровня квартала </li></ul></ul><ul><ul><ul><li>В случае меры SUM Год = SUM(Q1, Q2, Q3, Q4) </li></ul></ul></ul><ul><ul><ul><li>В случае меры MAX Год = MAX(Q1, Q2, Q3, Q4) </li></ul></ul></ul><ul><ul><ul><li>И т.д. </li></ul></ul></ul><ul><ul><li>С DISTINCT COUNT это не проходит </li></ul></ul>
  6. 6. Пример <ul><li>Анализируем журнал ISA Server </li></ul><ul><ul><li>Что и когда посещали пользователи </li></ul></ul><ul><ul><li>Интересует общее кол-во заходов, так и кол-во уникальных сайтов </li></ul></ul>http://msdn.microsoft.com/library/ 207046250121 0x30784346 Александр Гладченко 30.09.2002 19:30 0x30784333 0x30783430 0x30784346 0x30784345 0x30783346 0x30784346 0x30784333 0x30783432 0x30784431 0x30784333 0x30784333 IP_Binary URL IP_BigInt User_ID Time http://www.sql.ru 195209060199 Александр Гладченко 01.10.2002 22:00 http://www.hotsex.com 64239005092 Алексей Шуленин 01.10.2002 19:00 http://www.microsoft.com/sql 207046249027 Александр Гладченко 01.10.2002 17:00 http://www.hardcore.com 206126000001 Алексей Шуленин 01.10.2002 15:00 http://www.sqlmag.com 63088172065 Александр Гладченко 01.10.2002 11:00 http://www.microsoft.com/sql 207046249027 Александр Гладченко 01.10.2002 10:00 http://www.sql.ru 195209060199 Александр Гладченко 01.10.2002 0 9:00 http://www.xxx.com 66028153014 Алексей Шуленин 30.09.2002 19:45 http://www.sex.com 209081007023 Алексей Шуленин 30.09.2002 19:20 http://www.sql.ru 195209060199 Александр Гладченко 30.09.2002 19:10 http://www.sql.ru 195209060199 Александр Гладченко 30.09.2002 19:00
  7. 7. Пример <ul><li>Как следствие, увеличивается время процессинга, снижается масштабируемость </li></ul><ul><ul><li>Весь куб трактуется Analysis Services как неаддитивный </li></ul></ul><ul><ul><li>Имеет смысл не держать в нем других мер </li></ul></ul><ul><ul><ul><li>Выносить их в другие кубы и объединять в виртуальные </li></ul></ul></ul><ul><li>Накладывает на куб дополнительные ограничения </li></ul><ul><ul><li>Только одна мера такого типа может присутствовать в регулярном кубе </li></ul></ul><ul><ul><li>В кубе не допускаются измерения с пользовательскими свертками </li></ul></ul><ul><ul><ul><li>Custom Rollup Operators, Custom Rollup Formulas – см. далее </li></ul></ul></ul><ul><li>Эти ограничения не касаются виртуальных кубов </li></ul><ul><li>Либо эмулировать DISTINCT COUNT при пом. Calculated Members </li></ul><ul><li>Нижние агрегаты не помогают </li></ul><ul><ul><li>Исключение – измерения, построенные на member properties измерения, по к-му считается DISTINCT COUNT </li></ul></ul><ul><ul><li>Образуют непересекающиеся куски </li></ul></ul><ul><ul><ul><li>Напр., регион сайта </li></ul></ul></ul><ul><ul><li>Поэт. такая агр.ф-ция наз. полуаддитивной </li></ul></ul>4 8   2002 Total 3 5 4-й квартал   2 3 3-й квартал 2002 IP_Distinct IP_Count Квартал Год   Data     Александр Гладченко Чел
  8. 8. Как посмотреть коллекцию агрегатов <ul><li>DSO.ServerClass olap_server = new DSO.ServerClass(); </li></ul><ul><li>olap_server.Connect(&quot;localhost&quot;); </li></ul><ul><li>DSO.DatabaseClass olap_db = (DSO.DatabaseClass) olap_server.MDStores.Item(&quot;NW&quot;); </li></ul><ul><li>DSO.CubeClass olap_cube = (DSO.CubeClass) olap_db.Cubes.Item(&quot;Продажи&quot;); </li></ul><ul><li>DSO.PartitionClass olap_part = (DSO.PartitionClass) olap_cube.Partitions.Item(1); </li></ul><ul><li>Console.WriteLine(&quot;В дефолтовой партиции куба {0} содержится {1} агрегатов. Вот они:&quot;, olap_cube.Name, olap_part.MDStores.Count); </li></ul><ul><li>foreach (DSO.AggregationClass agg in olap_part.MDStores) </li></ul><ul><li>Console.Write(agg.Name + &quot; ; &quot;); </li></ul><ul><li>olap_server.CloseServer(); </li></ul><ul><li>a 1 …a n </li></ul><ul><ul><li>a i – уровень по i- му измерению </li></ul></ul>
  9. 9. Точнее – это множества агрегатов <ul><li>В ROLAP они видны как SELECT ы c GROUP BY по уровням </li></ul><ul><li>1142 </li></ul><ul><ul><li>По 4-му уровню 3-го измерения (Время - > Месяц) </li></ul></ul><ul><ul><li>По 2-му уровню 4-го измерения (Клиент - > Страна) </li></ul></ul><ul><li>Под 1-м уровнем понимается (All) </li></ul>
  10. 10. Структура таблицы агрегатов Имя раздела Имя куба Мера, агрегированная в соотв. с ее ф-цией GROUP BY по членам выбр. уровня
  11. 11. Вопрос на понимание <ul><li>Почему по региону она суммировала так: </li></ul><ul><li>INSERT INTO Продажи_Продажи_03 (Country_L12, Region_L13, SUM_LineItemFreight, ... ) </li></ul><ul><li>SELECT &quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;Country&quot; as Country_L12 , &quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;Region&quot; as Region_L13, SUM(&quot;dbo&quot;.&quot;Sales_Fact&quot;.&quot;LineItemFreight&quot;) As SUM_LineItemFreight, ... FROM &quot;dbo&quot;.&quot;Sales_Fact&quot;, &quot;dbo&quot;.&quot;Customer_Dim&quot; </li></ul><ul><li>WHERE (&quot;dbo&quot;.&quot;Sales_Fact&quot;.&quot;CustomerKey&quot;=&quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;CustomerKey&quot;) </li></ul><ul><li>GROUP BY &quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;Country&quot;, &quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;Region&quot; </li></ul><ul><li>А по городу так: </li></ul><ul><li>INSERT INTO Продажи_Продажи_04 (Country_L12, Region_L13, City_L14, SUM_LineItemFreight, ... ) </li></ul><ul><li>SELECT MIN (&quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;Country&quot;) as Country_L12 , MIN (&quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;Region&quot;) as Region_L13 , &quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;City&quot; as City_L14 , SUM(&quot;dbo&quot;.&quot;Sales_Fact&quot;.&quot;LineItemFreight&quot;) As SUM_LineItemFreight, ... </li></ul><ul><li>FROM &quot;dbo&quot;.&quot;Sales_Fact&quot;, &quot;dbo&quot;.&quot;Customer_Dim&quot; </li></ul><ul><li>WHERE (&quot;dbo&quot;.&quot;Sales_Fact&quot;.&quot;CustomerKey&quot;=&quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;CustomerKey&quot;) </li></ul><ul><li>GROUP BY &quot;dbo&quot;.&quot;Customer_Dim&quot;.&quot;City&quot; </li></ul>
  12. 12. Ответ <ul><li>Найдите 1 существенное отличие: </li></ul><ul><li>Если ключи на протяжении уровня неуникальны </li></ul><ul><ul><li>регион – в разных странах есть «Прочие регионы», </li></ul></ul><ul><li>то координаты члена - > цепочка с верхнего уровня иерархии </li></ul><ul><ul><li>GROUP BY Country, Region </li></ul></ul><ul><li>Если уникальны, то City однозначно определяет своих родителей на верхних уровнях ( Region и Country ) и тянуть их в GROUP BY не нужно </li></ul><ul><ul><li>MIN – чтобы включить родителей в SELECT; все равно дубликатов гарантированно не будет (при данном City) </li></ul></ul>
  13. 13. Последовательность расчета <ul><li>Сначала Analysis Service попробовала создать под агрегаты индексированные представления </li></ul><ul><ul><li>Почему это лучше, чем таблицы, и что для этого нужно – разбирали на Платформе </li></ul></ul><ul><ul><li>Обломалась, решила не выпендриваться </li></ul></ul><ul><li>3 уровня в Продуктах * 3 уровня в Сотрудниках * 5 уровней во Времени * 5 уровней в Клиенте = 225 агрегатных таблиц </li></ul><ul><li>Создала всего 39, остальные зажала </li></ul><ul><ul><li>Чем глубже лезет в младшие измерения, тем более небрежно агрегирует старшие </li></ul></ul><ul><li>Несмотря на это Design Storage Wizard пишет, что будет достигнуто 100% производительности </li></ul><ul><ul><li>Вывод: 100% не означает, что будут рассчитаны и положены в куб все возможные агрегаты </li></ul></ul>1112 1113 1114 1115 1121 1122 1123 1124 1125 1131 1132 1133 1134 1141 1142 1151 1211 1212 1213 1214 1221 1222 1231 1241 2111 2112 2113 2114 2121 2122
  14. 14. Задание принудительной агрегации в измерении <ul><li>При помощи св-ва AggregationUsage интерфейса Dimension </li></ul><ul><li>Имплементируется в классах ClsCubeDimension ( там оно Read-Write) и ClsPartitionDimension (там оно Read-Only, п.ч. наследуется от куба) </li></ul><ul><li>Принимает зн-я enum типа DimensionAggUsageTypes </li></ul><ul><ul><li>0 = dimAggUsageStandard – как clsAnalyzer на душу положит </li></ul></ul><ul><ul><li>1 = dimAggUsageTopOnly – считать агрегаты только для уровня All (= 1) </li></ul></ul><ul><ul><li>2 = dimAggUsageDetailsOnly – только для листового уровня </li></ul></ul><ul><ul><li>3 = dimAggUsageCustom – c м. след.слайд </li></ul></ul><ul><ul><li>4 = dimAggUsageTopAndDetailsOnly – понятно </li></ul></ul>
  15. 15. Задание принудительной агрегации в уровне <ul><li>При помощи св-ва EnableAggregations интерфейса Level </li></ul><ul><li>Имплементируется в классах clsCubeLevel (Read-Write) и clsPartitionLevel ( Read-Only ) </li></ul><ul><li>Если для родительского измерения AggregationUsage = dimAggUsageCustom , то </li></ul><ul><ul><li>True – рассматривать агрегаты для данного уровня </li></ul></ul><ul><ul><li>False – нет </li></ul></ul>
  16. 16. Последовательность выполнения многомерного запроса <ul><li>Посмотреть, может быть, результат уже содержится в кэше на данном клиенте? </li></ul><ul><li>Если нет, проверить серверный кэш </li></ul><ul><li>Если нет, посмотреть, можно ли удовлетворить запрос из имеющихся агрегатов </li></ul><ul><ul><li>Помним, что заказанные 100% произв-ти не гарантируют 100% агрегатов </li></ul></ul><ul><ul><li>Помним про semi-additive measures </li></ul></ul><ul><li>Если нет, то какие агрегаты еще нужно досчитать </li></ul><ul><ul><li>Помним, что при ROLAP за ними нужно лезть в источник </li></ul></ul><ul><li>Если агрегатов недостаточно, то взять детальные данные </li></ul><ul><ul><li>Помним, что при ROLAP и HOLAP за ними нужно лезть в источник </li></ul></ul>
  17. 17. Calculated Members <ul><li>Традиционно ассоциируются с вычисляемыми мерами </li></ul>
  18. 18. Calculated Members <ul><li>На самом деле может относиться к любому измерению </li></ul><ul><ul><li>Не обязательно Measures </li></ul></ul><ul><li>Задается как член, являющийся ребенком регулярного нелистового члена </li></ul><ul><ul><li>Сам, в свою очередь, не может иметь детей </li></ul></ul><ul><li>Задается вычисляемым в ходе запроса MDX-выражением </li></ul>
  19. 19. Пример <ul><li>Вот измерение «Время» </li></ul>Обратите внимание, что уровень «день» не показан - Calc Members не могут создаваться ниже листьев Определяем вычисляемый член под июлем 1996 г.
  20. 20. Пример <ul><li>Получили еще один «день» в июле 1996 г. </li></ul>
  21. 21. Отличие calc member от member property <ul><li>Member property </li></ul><ul><ul><li>Не увеличивает (хотя бы фиктивно) число ячеек в кубе </li></ul></ul><ul><ul><li>Подчиняется не члену-родителю, а уровню в целом </li></ul></ul><ul><ul><li>Вычисляется не при помощи MDX на основе других ячеек куба, а на основе данных операционного источника в его терминах ( SQL) </li></ul></ul>case when (DatePart(year, &quot;dbo&quot;.&quot;Time_Dim&quot;.&quot;TheDate&quot;) % 4 = 0 and DatePart(year, &quot;dbo&quot;.&quot;Time_Dim&quot;.&quot;TheDate&quot;) % 100 <> 0) or DatePart(year, &quot;dbo&quot;.&quot;Time_Dim&quot;.&quot;TheDate&quot;) % 1000 = 0 then 366 else 365 end
  22. 22. Создание calc member <ul><li>Масштаба запроса </li></ul><ul><ul><li>WITH MEMBER … AS ‘MDX- выражение ’ </li></ul></ul><ul><li>Масштаба сессии </li></ul><ul><ul><li>CREATE MEMBER … AS аналогично </li></ul></ul><ul><li>Масштаба куба </li></ul><ul><ul><li>Через DSO – см. след. слайд </li></ul></ul>
  23. 23. Создание calc member ... DSO.CubeClass olap_cube = (DSO.CubeClass) olap_db.Cubes.Item(&quot;Продажи&quot;); string CalcMemberName = &quot;Новый член&quot;; try { DSO.CubeCommandClass olap_cmd = (DSO.CubeCommandClass) olap_cube.Commands.Item(CalcMemberName); if (olap_cmd.CommandType == DSO.CommandTypes.cmdCreateMember) olap_cube.Commands.Remove(CalcMemberName); } catch (NullReferenceException e) {} finally { DSO.CubeCommandClass olap_cmd = (DSO.CubeCommandClass) olap_cube.Commands.AddNew(CalcMemberName, DSO.SubClassTypes.sbclsRegular); olap_cmd.CommandType = DSO.CommandTypes.cmdCreateMember; olap_cmd.Statement = &quot;CREATE MEMBER CURRENTCUBE.[Время].[Год].&[1996].&[3].&[7].[&quot; + CalcMemberName + &quot;] AS '[Время].CurrentMember.Parent.Name'&quot;; olap_cube.Update(); } olap_server.CloseServer();
  24. 24. Multicolumn measures <ul><li>Не обязательно прибегать к calc members , если агрегат задействует несколько колонок таблицы фактов </li></ul><ul><ul><li>В выражении - только арифметические операторы +, -, *, / </li></ul></ul><ul><ul><li>Вообще странно, что не понимает произвольного валидного в терминах операционного источника выражения </li></ul></ul><ul><li>Можно обойтись стандартной мерой </li></ul>
  25. 25. Дополнительные свойства Calculated Members по сравнению с мерами <ul><li>FORMAT_STRING, FORE_COLOR, BACK_COLOR, FONT_NAME, FONT_SIZE, … </li></ul><ul><li>Оцениваются динамически </li></ul><ul><li>Позволяют навести дополнительные красивости в отчетах централизованно на уровне сервера </li></ul><ul><ul><li>Если, конечно, клиент в курсе этих св-в </li></ul></ul><ul><li>Пример: </li></ul><ul><ul><li>with member Measures.[Рост продаж] as '([Measures].[Store Sales], Time.CurrentMember) - ([Measures].[Store Sales], Time.PrevMember)', FORE_COLOR = 'iif (Measures.[Рост продаж] < 0, rgb(255, 0, 0), rgb(0, 255, 0))', FORMAT_STRING = '#,#.00' </li></ul></ul><ul><ul><li>select Time.Members on rows, Store.[USA].Children on columns </li></ul></ul><ul><ul><li>from Sales where Measures.[Рост продаж] </li></ul></ul><ul><ul><li>CELL PROPERTIES FORE_COLOR, FORMATTED_VALUE </li></ul></ul>
  26. 26. Более сложный пример <ul><li>Если в целом по региону рост нормальный, но внутри есть потомки с отрицательным ростом, красить фон в желтый </li></ul><ul><ul><li>Обсуждение MDX не входит в цели доклада </li></ul></ul>with member Measures.[Рост продаж] as '([Measures].[Store Sales], Time.CurrentMember) - ([Measures].[Store Sales], Time.PrevMember)', FORE_COLOR = 'iif (Measures.[Рост продаж] < 0, rgb(255, 0, 0), rgb(0, 255, 0))', BACK_COLOR = 'iif (Count(Filter(Descendants(Store.CurrentMember, [Store City], SELF_AND_BEFORE), Measures.[Рост продаж] < 0)) > 0, rgb(255, 255, 0), rgb(255, 255, 255))' , FORMAT_STRING = '#,#.00' select Time.Members on rows, Descendants(Store.USA, [Store City], SELF_AND_BEFORE) on columns from Sales where Measures.[Рост продаж] CELL PROPERTIES FORE_COLOR, BACK_COLOR , FORMATTED_VALUE
  27. 27. Custom Rollup Formula <ul><li>Отменяет действие агрегатной функции меры и агрегирует детей по данной иерархии в соответствии с MDX-выражением в формуле </li></ul>Год - стандартная агрегация (сумма) Квартал – не сумма месяцев, а остаток за последний месяц
  28. 28. Custom Rollup Formula <ul><li>Применяется ко всем членам уровня </li></ul><ul><ul><li>Квартал - > Q1, Q2, Q3, Q4 </li></ul></ul><ul><ul><li>Если исключения, то iif: </li></ul></ul><ul><ul><ul><li>iif(Time.CurrentMember.Name = &quot;Q1&quot;, 0, Time.CurrentMember.LastChild) </li></ul></ul></ul><ul><li>Если определено для shared dimension, то действует во всех кубах, где оно участвует </li></ul><ul><ul><li>Можно отредактировать формулу свертки в измерении непосредственно для данного куба </li></ul></ul><ul><ul><ul><li>Cube Editor </li></ul></ul></ul><ul><ul><li>Т.е. для clsCubeDimension, а не clsDatabaseDimension </li></ul></ul>
  29. 29. Unary Operators <ul><li>С какими знаками члены агрегируются в своего родителя </li></ul><ul><li>В реляц.табл. соотв.поле, откуда берутся знаки для членов </li></ul>
  30. 30. Unary Operators <ul><li>Типичный пример измерения – счета </li></ul><ul><ul><li>+ - активы, - - пассивы, ~ - внебалансовые </li></ul></ul><ul><li>В случае некоммутативных операций </li></ul><ul><ul><li>Напр., у одного члена +, у брата * </li></ul></ul><ul><li>порядок в соответствии с order by уровня </li></ul>
  31. 31. Custom Member <ul><li>Идея – аналогично Unary Operators, функционал – шире </li></ul><ul><li>Вместо унарного оператора – MDX-формула, в соответствии с к-й получается значение данного члена </li></ul><ul><li>MDX, к-й будет применяться к первичному значению, также берется из строкового поля реляц.таблицы </li></ul>
  32. 32. Calculated Cells <ul><li>MDX- формула, применяемая к более общим областям куба </li></ul><ul><li>Calculation Subcube задается в виде набора измерений, каждое из которых ограничивается одним из след.способов – см.рис. </li></ul><ul><ul><li>Custom MDX должен сводиться к одному из вышестоящих вариантов </li></ul></ul>
  33. 33. Calculated Cells <ul><li>Calculation Condition позволяет дополнительно оговорить диапазон вычислений </li></ul><ul><ul><li>Что удобно для более тонкой фильтрации Subcube </li></ul></ul><ul><li>Собственно, формула вычислений для заданной области ячеек </li></ul>
  34. 34. Пример <ul><li>Применим формулу, аналогичную рассмотренной в Custom Rollup только к </li></ul><ul><ul><li>Продажам в штуках </li></ul></ul><ul><ul><li>штату Вашингтон (включая отнсящиеся к нему города, но не расположенные в них торговые точки) </li></ul></ul><ul><ul><li>Годам и первым двум кварталам в каждом году </li></ul></ul>with cell calculation Calc1 for '({Measures.[Unit Sales]}, DESCENDANTS(Store.[Store State].[WA], Store.[Store City]))' as 'Time.CurrentMember.FirstChild', condition = 'Time.CurrentMember.Level.Name = &quot;Year&quot; or Time.CurrentMember.Level.Name = &quot;Quarter&quot; and (Time.CurrentMember.Name = &quot;Q1&quot; or Time.CurrentMember.Name = &quot;Q2&quot;)' select Time.Members on rows, CrossJoin(Store.[USA].Children, {Measures.[Unit Sales], Measures.[Store Sales]}) on columns from Sales
  35. 35. Пример <ul><li>Видим, что все работает: </li></ul><ul><li>В 1997 г. и в 1-м и 2-м кварталах по мере Unit Sales сидит действительно цифра от FirstChild </li></ul><ul><li>По всем остальным областям (мере Store Sales, 3-му и 4-му кварталам) – по умолчанию (дети суммируются) </li></ul>
  36. 36. Взаимодействие пользовательских вычислений <ul><li>Что происходит, когда в одной ячейке сталкиваются </li></ul><ul><ul><li>Разные типы пользовательских вычислений </li></ul></ul><ul><ul><ul><li>Напр., Custom Rollup и Custom Member </li></ul></ul></ul><ul><ul><li>Два однотипных вычисления по разным осям </li></ul></ul><ul><ul><ul><li>Напр., два Calculated Members </li></ul></ul></ul>
  37. 37. Понятие SOLVE ORDER <ul><li>Пример </li></ul><ul><ul><li>CurrentMember везде можно опустить – просто, чтобы было понятно, что участвуют 2 измерения (как минимум) </li></ul></ul>with member Measures.[Прибыль] as '(Time.CurrentMember, [Measures].[Store Sales]) - (Time.CurrentMember, [Measures].[Store Cost])', format_string = '#,#.00' member Time.[Прирост в 4 кв.] as '(Time.[Q4], Measures.CurrentMember) / (Time.[Q3], Measures.CurrentMember)', format_string='#,#.000' select {Measures.[Store Cost], Measures.[Store Sales], Measures.[Прибыль]} on columns, {Time.[Q3], Time.[Q4], Time.[Прирост в 4 кв.]} on rows from Sales Здесь Доходы - Издержки Здесь 4-й кв-л / 3-й кв-л А здесь-то что: - столбцов или / строк ??? 1.300 1.303 Прирост 34219.51 56965.64 22746.13 Q4 26362.85 43825.97 17463.12 Q3 Прибыль Sales Cost
  38. 38. Понятие SOLVE ORDER <ul><li>Побеждает 2-я формула </li></ul><ul><li>Побеждает 1-я формула </li></ul>with member Measures.[Прибыль] as '[Measures].[Store Sales] - [Measures].[Store Cost]', format_string = '#,#.00', solve_order = 1 member Time.[Прирост в 4 кв.] as 'Time.[Q4] / Time.[Q3]', format_string='#,#.000' , solve_order = 2 select {Measures.[Store Cost], Measures.[Store Sales], Measures.[Прибыль]} on columns, {Time.[Q3], Time.[Q4], Time.[Прирост в 4 кв.]} on rows from Sales with member Measures.[Прибыль] as '[Measures].[Store Sales] - [Measures].[Store Cost]', format_string = '#,#.00', solve_order = 2 member Time.[Прирост в 4 кв.] as 'Time.[Q4] / Time.[Q3]', format_string='#,#.000' , solve_order = 1 select {Measures.[Store Cost], Measures.[Store Sales], Measures.[Прибыль]} on columns, {Time.[Q3], Time.[Q4], Time.[Прирост в 4 кв.]} on rows from Sales 1.298 1.300 1.303 Прирост 34219.51 56965.64 22746.13 Q4 26362.85 43825.97 17463.12 Q3 Прибыль Sales Cost .00 1.300 1.303 Прирост 34219.51 56965.64 22746.13 Q4 26362.85 43825.97 17463.12 Q3 Прибыль Sales Cost
  39. 39. Понятие SOLVE ORDER <ul><li>Solve Order можно видеть и менять только для Calculated Members и Calculated Cells </li></ul><ul><ul><li>Таким образом, для них столкновение интересов разрешается при помощи Solve Order </li></ul></ul><ul><li>У всех остальных типов рассмотренных пользовательских агрегаций он недоступен </li></ul><ul><ul><li>Можно считать, что он < 0, поэтому они заведомо проигрывают calc members и cells </li></ul></ul><ul><li>Если на одну ячейку приходится Custom Rollup (Rollup Formula или дети с унарными операторами) и Custom Member </li></ul><ul><ul><li>Выигрывает Custom Member Formula </li></ul></ul><ul><li>Если ячейка имеет Rollup Formula , а дети – Unary Operators </li></ul><ul><ul><li>Выигрывает Rollup Formula </li></ul></ul>
  40. 40. Однотипные вычисления по разным осям <ul><li>Т.е. если Solve Order одинаковый </li></ul><ul><li>Выигрывает последняя ось в кубе </li></ul><ul><ul><li>Этот порядок можно менять </li></ul></ul><ul><ul><li>Куб после этого придется перепроцессить </li></ul></ul><ul><li>Т.е. можно считать, что чем каждая ось немного добавляет к Solve Order </li></ul>
  41. 41. Понятие CALCULATION PASS <ul><li>Пример 1 </li></ul><ul><ul><li>Сделать область вычисляемых ячеек, в которой значение каждой ячейки удваивается </li></ul></ul><ul><ul><li>Первое, что приходит на ум: </li></ul></ul><ul><ul><ul><li>with cell calculation Calc1 for '({Measures.[Unit Sales]})' as 'Measures.[Unit Sales] * 2' </li></ul></ul></ul><ul><ul><ul><li>select Time.Members on rows, Store.[USA].Children on columns from Sales where Measures.[Unit Sales] </li></ul></ul></ul><ul><ul><li>Что немедленно дает ошибку Infinite recursion detected during execution of calculated member </li></ul></ul><ul><ul><li>Чтобы избежать зацикливания, необходимо брать значение с предыдущего шага вычислений </li></ul></ul><ul><ul><ul><li>with cell calculation Calc1 for '({Measures.[Unit Sales]})' as ' CalculationPassValue(Measures.[Unit Sales], -1, RELATIVE) * 2' </li></ul></ul></ul><ul><ul><ul><li>select Time.Members on rows, Store.[USA].Children on columns from Sales where Measures.[Unit Sales] </li></ul></ul></ul>
  42. 42. Понятие CALCULATION PASS <ul><li>Пример 2 </li></ul><ul><ul><li>Измерения Parent-Child с опцией Non-leaf data hidden </li></ul></ul><ul><ul><li>Когда данные на узлах не агрегируются с нижних уровней, а берутся напрямую из источника (как листья) </li></ul></ul><ul><li>В этом случае Rollup Formula уровня неявно получает следующий вид </li></ul><ul><ul><li>CalculationPassValue( Employees .CurrentMember.DataMember, 0) </li></ul></ul>
  43. 43. Номер прохода <ul><li>Итак, имеем ту же вводную, что и для SOLVE ORDER – несколько формул на одну ячейку </li></ul><ul><ul><li>SOLVE ORDER назначает победителя, отвергая остальных </li></ul></ul><ul><ul><li>CALCULATION PASS позволяет применить несколько вычислений к одной ячейке и установить порядок их выполнения </li></ul></ul><ul><li>CALCULATION PASS = 0 </li></ul><ul><ul><li>Извлечение данных из источников, расчет custom members и calculated members </li></ul></ul><ul><li>CALCULATION PASS = 1 </li></ul><ul><ul><li>Агрегирование: вычисления унарных операторов членов и rollup- формул </li></ul></ul><ul><li>Менять значение CALCULATION PASS можно только у Calculated Cells </li></ul><ul><ul><li>1 (по умолчанию) и выше </li></ul></ul>
  44. 44. Пример <ul><li>select DrilldownLevel({Time.[1997]}) on rows, {Customers.[All Customers]} on columns from Sales where Measures.[Store Sales] </li></ul><ul><li>Пусть хотим сделать </li></ul><ul><ul><li>Q3 = 2 * Q4 </li></ul></ul><ul><ul><li>Q4 = 2 * Q3 </li></ul></ul><ul><li>with cell calculation Calc_Q3 for '({Measures.[Store Sales]}, {Time.[1997].[Q3]})' as 'CalculationPassValue((Time.[Q4], Measures.[Store Sales]), -1, RELATIVE) * 2' </li></ul><ul><li>cell calculation Calc_Q4 for '({Measures.[Store Sales]}, {Time.[1997].[Q4]})' as 'CalculationPassValue((Time.[Q3], Measures.[Store Sales]), -1, RELATIVE) * 2' </li></ul><ul><li>select … </li></ul>152 671.62 Q4 140 271.89 Q3 132 666.27 Q2 139 628.35 Q1 565 238.13 1997 All Customers
  45. 45. Пример <ul><li>Теперь слегка изменим пример </li></ul><ul><ul><li>with cell calculation Calc_Q3 for '({Measures.[Store Sales]}, {Time.[1997].[Q3]})' as 'CalculationPassValue((Time.[Q4], Measures.[Store Sales]), -1, RELATIVE) * 2', calculation_pass_number = 1 </li></ul></ul><ul><ul><li>cell calculation Calc_Q4 for '({Measures.[Store Sales]}, {Time.[1997].[Q4]})' as 'CalculationPassValue((Time.[Q3], Measures.[Store Sales]), -1, RELATIVE) * 2', calculation_pass_number = 2 ... </li></ul></ul><ul><li>Шаг 0 </li></ul><ul><li>Шаг 1 </li></ul>* 2 280 543.78 Q4 305 343.24 Q3 132 666.27 Q2 139 628.35 Q1 858 181.64 1997 All Customers 152 671.62 Q4 140 271.89 Q3 132 666.27 Q2 139 628.35 Q1 565 238.13 1997 All Customers
  46. 46. Оценка и вычисление <ul><li>Вопрос </li></ul><ul><ul><li>Почему поменялась сумма в 1997? </li></ul></ul><ul><ul><li>Ведь раньше говорилось, что все агрегаты считаются не позже 1-го шага? </li></ul></ul><ul><li>Потому что оценка и вычисление ячейки – это разные вещи </li></ul><ul><ul><li>Оценка начинается с максимального Pass Number и идет вниз, запоминая, от каких ячеек зависит данная </li></ul></ul><ul><ul><li>На шаге 0 получает первичные значения и поднимается обратно вверх, вычисляя значения и разрешая ссылки </li></ul></ul><ul><ul><li>Рассмотрим на примере единственной ячейки </li></ul></ul><ul><li>Шаг 0 </li></ul><ul><li>Шаг 1 </li></ul>* 2 <ul><li>Шаг 2 </li></ul>* 2 280 543.78 Q4 305 343.24 Q3 132 666.27 Q2 139 628.35 Q1 858 181.64 1997 All Customers 152 671.62 Q4 140 271.89 Q3 132 666.27 Q2 139 628.35 Q1 565 238.13 1997 All Customers 610 686.48 Q4 305 343.24 Q3 132 666.27 Q2 139 628.35 Q1 1 188 324.34 1997 All Customers
  47. 47. Пример <ul><li>with cell calculation Test for '({Measures.[Sales Count]}, {Time.[1997].Q1}, {Store.USA.WA.Seattle}, {Product.Drink.[Alcoholic Beverages].[Beer and Wine].Wine.Portsmouth.[Portsmouth Chardonnay]})' as 'CalculationPassValue(Measures.[Sales Count], -1, RELATIVE) * 2', calculation_pass_number = 5, calculation_pass_depth = 3 </li></ul><ul><li>select DrilldownLevel({Time.[1997]}) on rows, {Store.USA.WA.Seattle} on columns from Sales where (Measures.[Sales Count], Product.Drink.[Alcoholic Beverages].[Beer and Wine].Wine.Portsmouth.[Portsmouth Chardonnay]) </li></ul><ul><ul><li>calculation_pass_depth – сколько шагов отмотать назад, чтобы оценить выражение </li></ul></ul>2 Q4 2 Q3 1 Q2 1 Q1 6 1997 Seattle
  48. 48. Что происходит <ul><li>Оценка </li></ul><ul><li>Вычисление </li></ul>Шаг 4 Шаг 5 Шаг 3 Шаг 0 1 Q1 Seattle 2 * Q1 Seattle 2 * Q1 Seattle 2 Q1 Seattle 4 Q1 Seattle 8 Q1 Seattle 2 * Q1 Seattle
  49. 49. Вопросы?

×