Расчет DAX с диапазоном дат выполняется плохо - PullRequest
1 голос
/ 09 апреля 2020

У меня есть формула DAX, которая работает очень плохо, и, надеюсь, кто-то здесь может предложить решение.

У меня есть таблица, которая содержит около 400000 строк данных. ProductID (пример поля), startdate, enddate и поле флага IsActive. Данные из этой таблицы должны быть представлены несколькими способами. В некоторых отчетах я хочу видеть все активные продукты за выбранный период времени, а в других отчетах я хочу видеть только количество продуктов, которые были активны в последний день месяца.

Итак Я создал два запроса DAX для вычисления этого.

Сначала я вычисляю активные продукты:

_Calc_Count Fields :=
CALCULATE (
    DISTINCTCOUNT ( MyFactTable[ProductID] ),
    FILTER (
        MyFactTable,
        MyFactTable[StartDate] <= CALCULATE ( MAX ( 'Date'[Date] ) )
            && MyFactTable[EndDate] >= CALCULATE ( MIN ( 'Date'[Date] ) )
    ),
    MyFactTable[IsActive] = 1
)

Обратите внимание, что отчет, в котором используются эти вычисления, также может содержать диапазон дат (даже целый год (или несколько лет) может быть выбран с начальной и конечной датой, выбранными в фильтре). Отчет также разделен на другие фильтры, такие как Группа клиентов.

Затем у меня есть второе вычисление, которое использует первое и применяет функцию LASTNONBLANK:

Last Non Blank Value :=
CALCULATE (
    [_Calc_Count Fields],
    LASTNONBLANK ( 'Date'[Date], [_Calc_Count Fields] )
)

Оба вычисления очень, очень медленные .

Кто-нибудь может предложить лучший подход? Можно ли оптимизировать формулу DAX или полностью переписать?

пс. Я использую табличную модель служб аналитики.

Заранее благодарю всех за ответы!

1 Ответ

0 голосов
/ 09 апреля 2020

Есть много моментов для оптимизации.

Прежде всего, вам необходимо понять, где находится узкое место.
Я бы сделал три отдельных предварительных теста:
A) изменил DISTINCTCOUNT с простым COUNT
B) Удалите ФИЛЬТР
C) Удалите IsActive

Тогда вы сможете понять, где расставить приоритеты в своих усилиях, однако есть некоторые очень простые общие оптимизации, которые вы можете сделать в любом случае :

1. Используйте переменные, поэтому формула будет иметь вид:

 _Calc_Count Fields 3:=
VAR _startdate = CALCULATE ( MAX ( 'Date'[Date] ) )
VAR _enddate = CALCULATE ( MIN ( 'Date'[Date] ) )
RETURN
CALCULATE (
    DISTINCTCOUNT ( MyFactTable[ProductID] ),
    FILTER (
        MyFactTable,
        MyFactTable[StartDate] <= _startdate 
            && MyFactTable[EndDate] >= _enddate
    ),
    MyFactTable[IsActive] = 1
)

2. Если вы используете в качестве первого параметра FILTER всю таблицу фактов, Storage Engine загрузит в память Расширенная таблица , которая стоит очень дорого. Следовательно, в качестве второго шага формула должна выглядеть следующим образом:

_Calc_Count Fields 2:=
VAR _startdate = CALCULATE ( MAX ( 'Date'[Date] ) )
VAR _enddate = CALCULATE ( MIN ( 'Date'[Date] ) )
RETURN
CALCULATE (
    DISTINCTCOUNT ( MyFactTable[ProductID] ),
    MyFactTable[StartDate] <= _startdate && MyFactTable[EndDate] >= _enddate,
    MyFactTable[IsActive] = 1
)

Далее, на основе предварительного теста вы можете решить, куда инвестировать свои усилия.
Проблема в DISTINCTCOUNT:
- исследовать некоторые альтернативные алгоритмы для аппроксимации DISTINCTCOUNT (HIGH EFFORT)
- попробуйте отсортировать в источнике данных (back-end) таблицу по ProductId, чтобы обеспечить лучшее сжатие в AAS
- убедитесь, что ProductId является целочисленным типом данных с кодировкой Подсказка: значение

Проблема в ФИЛЬТРЕ:
- Попробуйте изменить «&&» на «,» (НИЗКОЕ УСИЛЕНИЕ)
- Исследовать количество элементов StartDate и EndDate. Если это DateTime, удалите часть времени. (LOW EFFORT)
- Попробуйте изменить источник данных в фоновом режиме и отсортировать по полезным полям (например, StartDate как c, поэтому, когда AAS будет читать таблицу, может произойти лучшее сжатие (LOW EFFORT)
- Убедитесь, что StartDate и Date относятся к типу данных Whole Number, с подсказкой о кодировке: значение (LOW EFFORT)

...