AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 20.12.2016, 17:45   #1  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Angry Тормозит создание буфера.
Привет всем.
Обнаружил неприятную особенность виртуальных компаний.
Если табличка включена в виртуальную компанию то создание буфера может тормозить и занимать гигантское время (у нас до 1,2 миллисекунд).
Неважно каким способом создавать буфер.
common.data() // дублирование
dictTable.MakeRecord()
map.lookup() // достаем из мапа
conPeek(con, 1) // достаем из контейнера

Важно условие - длительность тормозов прямо зависит от числа компаний в системе (примерно линейная зависимость наблюдается). У нас 280 компаний - для такого количества порядка 1 миллисекунды торможение. Казалось бы немного но при работе с разными выгрузками когда обрабатываются десятки тысяч записей эти миллисекунды превращаются в минуты.

Интересно, что если буфер создавать в компании dat, которая не включена в виртуальную компанию, то все быстро. Т.е. глюк проявляется в зависимости от того в какой компании создается буфер.

Обнаружили случайно - была выгрузка остатков, которая в цикле перебирала мап из 20 тысяч элементов, на каждом шаге дочитывала настроечную табличку из 5 записей из БД. Решили оптимизировать - положили эти 5 записей в мап и стали брать из мапа, а оно стало медленнее работать раза в 2
Оказалось, что в наших условиях запрос к БД длился 0,5 миллисекунд, а создание нового буфера (при доставании из мапа) длилось 1,2 миллисекунды, что привело к замедление выгрузки секунд на 30.

Как можно это обойти:
1. Выкинуть буфер из виртуальной компании. (отключить saveDataPercompany для него и создать свое кастомизированное поле с кодом компании)
или
2. Постараться изменить код чтобы часто не создавать табличный буфер.
или
3. Если надо хранить данные буфера в мапе или другому подобном хранилище, то меняем мап с хранения табличных буферов на контейнеры и реализуем на буфере методы pack и unpack и работаем с буфером дальше. Только в процессе работы экземпляр таблички не пересоздаем а вызываем на нем unpack передавая в аргументы контейнер который достали из мапа.

P.S.
Проверял все на версии 2009 (воспроизводится на билдах ядра 1600.3596 и 1500.4570 (RU7))

Последний раз редактировалось Logger; 20.12.2016 в 17:52.
За это сообщение автора поблагодарили: Pustik (3), gl00mie (3), S.Kuskov (5), dech (3).
Старый 20.12.2016, 17:45   #2  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Вот набросал джобик для проверки
X++:
static void Job3798_3(Args _args)
{
    VirtualDataAreaList     virtualDataAreaList;
    Dataarea                Dataarea;
    int                     tick1;
    int                     tick2;
    int                     i;
    DictTable               dictTable;
    common                  common;
    common                  common2;
    container               contable =

//        [tableNum(LEDGERJOURNALPOSTCONTROLUSERGROUP), "100"] // time 0,19     steps 20000  table   LedgerJournalPostControlUserGroup (company = 100)
//        [tableNum(LEDGERJOURNALPOSTCONTROLUSERGROUP), "dat"] // time 0,17     steps 20000  table   LedgerJournalPostControlUserGroup (company = dat)

//        [tableNum(LEDGERBALANCESHEETDIMFILEFORMAT), "100"] // time 0,17     steps 20000  table   LedgerBalanceSheetDimFileFormat (company = 100)
//        [tableNum(LEDGERBALANCESHEETDIMFILEFORMAT), "dat"] // time 0,19     steps 20000  table   LedgerBalanceSheetDimFileFormat (company = dat)

//        [tableNum(SalesTable), "100"] // time 0,25     steps 20000  table   SalesTable (company = 100)
//        [tableNum(SalesTable), "dat"] // time 0,25     steps 20000  table   SalesTable (company = dat)

//        [tableNum(DIRPARTYADDRESSRELATIONSHIPMAPPING), "100"] // time 10,25     steps 20000  table   DirPartyAddressRelationshipMapping (company = gab)  win2003    - CPU 2,6 GHz
                                                                // time 18,55     steps 20000  table   DirPartyAddressRelationshipMapping (company = gab)  win2008 R2 - CPU 2,3 GHz
//        [tableNum(DIRPARTYADDRESSRELATIONSHIPMAPPING), "dat"]   // time 10,19     steps 20000  table   DirPartyAddressRelationshipMapping (company = gab)
                                                                // time 19,73     steps 20000  table   DirPartyAddressRelationshipMapping (company = gab)  win2008 R2

//        [tableNum(CustTable), "100"] // time 10,08     steps 20000  table   CustTable (company = hld) - win2003
                                     // time 0,22     steps 20000  table   CustTable (company = dat) - win2008 R2
//        [tableNum(CustTable), "dat"] // time 0,22     steps 20000  table   CustTable (company = dat)

//        [tableNum(SysUserLog), "100"] // time 0,20     steps 20000  table   SysUserLog (company = No savePerCompany) - win2008 R2
//        [tableNum(SysUserLog), "dat"] // time 0,19     steps 20000  table   SysUserLog (company = No savePerCompany)  - win2008 R2


        [tableNum(GRD_SpecialDeptsInventLocations), "100"] // time 14,02     steps 20000  table   GRD_SpecialDeptsInventLocations (company = msc) for win2003
                                                           // time 27,16     steps 20000  table   GRD_SpecialDeptsInventLocations (company = msc) for win2008 R2

//        [tableNum(GRD_SpecialDeptsInventLocations), "dat"] // time 0,16     steps 20000  table   GRD_SpecialDeptsInventLocations (company = dat)  for win2003
                                                           // time 0,19     steps 20000  table   GRD_SpecialDeptsInventLocations (company = dat)  for win2008 R2
        ;

    ;
    appl.setDefaultCompany(conPeek(contable, 2));
    dictTable = new SysDictTable(conPeek(contable, 1));
    common = dictTable.makeRecord();
    common.(fieldNum(common, recid)) = 123; // force kernel to create a buffer instance

    select count(recId) from Dataarea where Dataarea.isVirtual;
    info(strFMT("count VirtCompanies = %1", Dataarea.RecId));

    select count(recId) from Dataarea where !Dataarea.isVirtual;
    info(strFMT("count Companies = %1", Dataarea.RecId));

    if (!dictTable.dataPrCompany())
    {
        info("Not percompany table");
    }
    else
    if (xDataarea::find(common.dataAreaId).isVirtual)
    {
        select count(recid) from virtualDataAreaList where virtualDataAreaList.virtualDataArea == common.dataAreaId;
        info(strFMT("table %1  contains  %2  companies for virtual %3", dictTable.name(), virtualDataAreaList.RecId, common.dataAreaId));
    }
    else
    {
        info(strFMT("table %1 is not virtual for company %2", dictTable.name(), common.dataAreaId));
    }

    tick1 = WinApi::getTickCount();
    i = 0;

    for (i = 1; i < 20000; i++)
    {
        common2 = common.data(); // make a buffer copy
        // also runs slowly with :
        // common2 = conpeek(con, 1);
        // common2 = map.lookup(1);
        // every time you create an instance of buffer
    }
    tick2 = WinApi::getTickCount();
    info(strFMT(
        "time %1     steps %2  table   %3 (company = %4)",
        (tick2-tick1)/1000,
        i,
        dictTable.name(),
        dictTable.dataPrCompany() ? common.dataAreaId : "No savePerCompany"
        ));

}
Старый 20.12.2016, 21:09   #3  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1243 (44) ++++++++
Регистрация: 11.04.2008
Попробуйте по-трейспарсить?
Старый 21.12.2016, 11:31   #4  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от DSPIC Посмотреть сообщение
Попробуйте по-трейспарсить?
Думаете я этого не делал ?
Джоб, это выжимка чтобы удобнее проиллюстрировать багу.
Старый 22.12.2016, 17:53   #5  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
К слову, о трейспарсере. Cразу забыл написать о его баге, а тут еще по джобу замерял, чтобы точно никакие сторонние эффекты не влияли.

Как выяснилось хваленный trace parcer нам врет. Он не всегда корректно показывает Exclusive time и Inclusive time.

Пример трейса кода:
Нажмите на изображение для увеличения
Название: ProductiveExaple.png
Просмотров: 298
Размер:	46.3 Кб
ID:	11107

видно, что если просуммировать время указанное trace parcer - нигде мы не получим даже 0,2 миллисекунды, а реально там каждый шаг цикла длился 1-1,5 миллисекунды. Т.е. какие-то действия он не фиксирует и на них тратится существенное время.
Как это поймать ?
Выделяем строку в трейсе, потом щелкаем правой кнопкой мыши по другой строке - во всплывающем меню он предложит нам вывести время между событиями. Вот оно корректно отображается. В нашем случае 1,37 миллисекунды.

Последний раз редактировалось Logger; 22.12.2016 в 18:14.
Старый 22.12.2016, 18:03   #6  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
А вот я джобик замерял.
Это медленный вариант - в рабочей компании.
Нажмите на изображение для увеличения
Название: SlowSpecialJobExample.png
Просмотров: 346
Размер:	51.1 Кб
ID:	11108

А это быстрый - в компании dat которая не включена в виртуальные.
Нажмите на изображение для увеличения
Название: FastSpecialJobExample.png
Просмотров: 405
Размер:	51.1 Кб
ID:	11109

трейсы внешне одинаковые.

Только в одном случае джоб выполнил 20 тысяч циклов за 25 секунд, а в другом за 0,5 секунды.

Так что trace parcer-у тоже верить нельзя. Все надо перепроверять.
За это сообщение автора поблагодарили: GannexMan (1).
Теги
trace parser, trace parser bug, virtual company, баг, виртуальные компании, производительность, трассировка

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Тормозит разноска Заказа на Покупку с ОС vazerdim DAX: Функционал 6 24.10.2012 22:04
SQL Server 2005, 2008: Создание недостающих индексов Poleax DAX: Прочие вопросы 6 05.06.2010 01:28
CRM создание писем и их рассылка - в чем трабл? ShadowFromXZone DAX: Функционал 9 17.06.2008 16:51
Создание буфера обмена на бездисковых станциях Владимир Максимов DAX: Программирование 9 03.04.2008 11:41
Импорт из буфера vey DAX: Программирование 13 27.06.2006 16:46
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 05:29.