Операции сортировки (Order()) и суммирования (Sum() по набору) могут быть одними из самых затратных с точки зрения производительности, особенно на больших наборах.
Оптимизация сортировки (Order())
1. Применяйте NON EMPTY перед сортировкой: Это самое важное правило. Сортировка меньшего набора данных всегда быстрее.
○ Плохо: Order([Product].[Product].[Product Name].Members, [Measures].[Sales Amount], BDESC) (сортирует все продукты, включая те, у которых нет продаж).
○ Хорошо: NON EMPTY Order([Product].[Product].[Product Name].Members, [Measures].[Sales Amount], BDESC) (сначалаудаляетпустыепродукты, затемсортирует).
○ Лучше: Order(NON EMPTY [Product].[Product].[Product Name].Members, [Measures].[Sales Amount], BDESC) (хотя NON EMPTY долженбытьпервымнаоси, внутри Order онможетбытьпримененкнабору, чтобыуменьшитьегоразмерпередсортировкой).
2. Используйте TopCount() / BottomCount() для "топ-N" выборок: Если вам нужен только определенный "топ-N" элементов, используйте TopCount() или BottomCount() вместо того, чтобы сортировать весь набор, а затем брать первые N. Эти функции оптимизированы для этой задачи.
Пример: Топ-5 самых продаваемых продуктов AdventureWorks за 2007 год
SELECT
[Measures].[Sales Amount] ON COLUMNS,
TopCount(
NON EMPTY [Product].[Product].[Product Name].Members, -- Сначала убираем пустые
5,
([Measures].[Sales Amount], [Date].[Calendar Year].&[2007])
) ON ROWS
FROM
[Adventure Works]
WHERE
[Date].[Calendar Year].&[2007]
3. Сортировка по атрибутам: Если возможно, сортируйте по атрибутам, которые имеют индексы в кубе, или по свойствам членов, а не по сложным выражениям.
Оптимизация суммирования (Sum())Функция Sum() в MDX может быть использована для суммирования меры по набору. Ее производительность сильно зависит от размера набора, по которому она итерирует.
1. Минимизируйте размер набора для Sum():
○ Используйте NON EMPTY: Если вы суммируете по набору, который может содержать пустые элементы, используйте NON EMPTY для создания этого набора.
○ Фильтруйте набор до Sum(): Применяйте Filter() к набору перед передачей его в Sum(), если вам нужно суммировать только подмножество элементов.
Пример: Сумма продаж только для клиентов из Северной Америки в 2007 году
WITH MEMBER [Measures].[Sales North America 2007] AS
Sum(
Filter(
[Customer].[Customer].[Customer].Members,
([Measures].[Sales Amount], [Geography].[Sales Territory].[Sales Territory Group].&[North America], [Date].[Calendar Year].&[2007]) > 0
),
[Measures].[Sales Amount]
)
, FORMAT_STRING = "Currency"
SELECT
[Measures].[Sales North America 2007] ON COLUMNS
FROM
[Adventure Works]
Разбор:
○ Здесь Filter создает набор только тех клиентов, у которых были продажи в Северной Америке в 2007 году, а затем Sum агрегирует [Sales Amount] только по этому отфильтрованному набору. Это гораздо эффективнее, чем суммировать по всем клиентам, а затем пытаться отфильтровать.
2. Используйте агрегации куба: Если вы часто суммируете одну и ту же меру по определенным измерениям, убедитесь, что в кубе созданы соответствующие агрегации. Это позволяет движку использовать предварительно вычисленные значения, а не пересчитывать их каждый раз.
3. Избегайте избыточных вычислений внутри Sum(): Выражение, которое суммируется, должно быть максимально простым. Если оно содержит сложные расчетные элементы или функции, это может замедлить итерацию.