Показать сообщение отдельно
Старый 02.03.2013, 15:29   #1  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,158 / 1286 (47) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
DAX4: генератор финснсовой отчетности, выборка оборотов по корреспонденции счетов
Ни для кого не является секретом, что при настройке в ГФО выборки оборотов по счетам в корреспонденции с другими счетами работа ГФО становится не очень быстрой.
Раньше мы мирились с данной особенностью, но, в последнее время, пользователей стали эти особенности раздражать, пришлось искать методы оптимизации.
Формирование запроса на выборку в условиях корреспонденции производится в методе initQuery класса LedgerRRGOp_Ledger_Trans_RU. В DAX4 у нас загружены практически все изменения, существовавшие на момент прекращения поддержки DAX4. Ветка, которая относится к формированию запроса по корреспонденции
X++:
        case LedgerRRGOperationType_RU::TurnoverInCorr:
        case LedgerRRGOperationType_RU::TurnoverInCorrDebit:
        case LedgerRRGOperationType_RU::TurnoverInCorrCredit:
В стандарте выглядит так:
X++:
            this.addTransDateRange(parms.transDatePeriodFilter(baseDate));
            this.addRange(fieldnum(LedgerTrans, BondBatch_RU), SysQuery::valueNotEmptyString());
            this.addRange(fieldnum(LedgerTrans, BondBatchTrans_RU), SysQuery::valueNotEmptyString());
            offsetQueryBuildDatasource = queryBuildDataSource.addDataSource(tablenum(LedgerTrans));
            offsetQueryBuildDatasource.joinMode(JoinMode::ExistsJoin);
            offsetQueryBuildDatasource.addLink(fieldnum(LedgerTrans, TransDate), fieldnum(LedgerTrans, TransDate));
            offsetQueryBuildDatasource.addLink(fieldnum(LedgerTrans, Voucher), fieldnum(LedgerTrans, Voucher));
            offsetQueryBuildDatasource.addLink(fieldnum(LedgerTrans, BondBatch_RU), fieldnum(LedgerTrans, BondBatch_RU));
            offsetQueryBuildDatasource.addLink(fieldnum(LedgerTrans, BondBatchTrans_RU), fieldnum(LedgerTrans, BondBatchTrans_RU));
            offsetQueryBuildDatasource.addRange(fieldnum(LedgerTrans, AccountNum)).value(parms.offsetAccountFilter());
            offsetQueryBuildDatasource.addRange(fieldnum(LedgerTrans, PeriodCode)).value(SysQuery::value(PeriodCode::Regular));
            offsetQueryBuildDatasource.addRange(fieldnum(LedgerTrans, Crediting)).value(#CreditingQueryValue);
После оптимизации эта ветка выглядит так:
X++:
            this.addTransDateRange(parms.transDatePeriodFilter());
            this.addRange(fieldnum(LedgerTrans, BondBatch_RU), SysQuery::valueNotEmptyString());
            this.addRange(fieldnum(LedgerTrans, BondBatchTrans_RU), SysQuery::valueNotEmptyString());
            offsetQueryBuildDatasource = queryBuildDataSource.addDataSource(tablenum(LedgerTrans));

            // Изменил соединение с Exist на Inner с группировкой по RecId, убрал лишние условия соединения
            // Добавил подсказки на Query по порядку обработки таблиц запроса
            offsetQueryBuildDatasource.joinMode(JoinMode::InnerJoin);
            offsetQueryBuildDatasource.addSelectionField(fieldNum(LedgerTrans, RecId), SelectionField::Min);
            offsetQueryBuildDatasource.orderMode(OrderMode::GroupBy);

            query.forceSelectOrder(true);
            query.forceNestedLoop(true);

            offsetQueryBuildDatasource.addLink(fieldnum(LedgerTrans, BondBatch_RU), fieldnum(LedgerTrans, BondBatch_RU));
            offsetQueryBuildDatasource.addLink(fieldnum(LedgerTrans, BondBatchTrans_RU), fieldnum(LedgerTrans, BondBatchTrans_RU));

            offsetQueryBuildDatasource.addRange(fieldnum(LedgerTrans, AccountNum)).value(parms.offsetAccountFilter());
            offsetQueryBuildDatasource.addRange(fieldnum(LedgerTrans, PeriodCode)).value(SysQuery::value(PeriodCode::Regular));
            offsetQueryBuildDatasource.addRange(fieldnum(LedgerTrans, Crediting)).value(#CreditingQueryValue);
Как видно из приведенного кода, выполнены следующие изменения:
  • Изменен тип соединения и, на всякий случай, в связаннойм запросе сделана группировка.
  • Оптимизатору дана подсказка по поводу порядка выборки данных таблиц.
  • Убраны лишние условия соединения.
Мониторинг запросов в MS SQL показал:
  • В исходном варианте в случае выборки по 3-5 счетам главной таблицы и 2-3 счетам корреспонденции среднее время выборки по одной строке ГФО составляло 15000-26000 миллисекунд.
  • После изменения типа соединения среднее время составляло 2000 - 5000 миллисекунд.
  • После добавления подсказки оптимизатору среднее время сократилось до 90-150 миллисекунд.
В итоге время формирования отчета вместо 30-90 минут стало в районе 5-10 минут. Вроде бы проблему решили, но переносить эти изменения в рабочую базу как-то страшно.
В настройке наших отчетов данные до изменения и после изменения выдаются одни и те же, только кратно ускорилась работа отчета. Боюсь, что я что-то не учел и на других настройках ГФО просто начнет выдавать неправильные данные.
Просьба, если у кого-либо будет время, проанализировать эти изменения с точки зрения того, что может быть нарушено.

Последний раз редактировалось Raven Melancholic; 02.03.2013 в 15:33.