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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 15.12.2011, 02:12   #21  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от glibs Посмотреть сообщение
Прав был Wamr, когда советовал на больших объемах временные таблицы не использовать...
А что вместо них ? Постоянные таблички ?
Старый 15.12.2011, 02:20   #22  
glibs is offline
glibs
Member
Сотрудники компании It Box
Most Valuable Professional
Лучший по профессии 2011
Лучший по профессии 2009
 
4,942 / 911 (40) +++++++
Регистрация: 10.06.2002
Адрес: I am from Kyiv, Ukraine. Now I am in Moscow. For private contacts: glibs@hotmail.com
Мои исследования начались с попыток "прокачать" движок глобального поиска (реальная прикладная задача).

Похоже что когда количество данных у меня достигнет определенного предела — вместо временных табличек таки придется написать что-то другое. Либо в 6.0 что-то изменится. Я слышал про планы переноса временных таблиц в SQL СУБД.

Посмотрим...

Если припрет — отпишу чем все закончилось.

Вообще... либо постоянные таблицы, либо мапы...

Но на таких объемах запись в постоянные таблицы тоже не будет быстрой. Особенно если их еще и индексами снабдить.
__________________
С уважением,
glibs®
Старый 15.12.2011, 10:05   #23  
Pustik is offline
Pustik
Участник
 
807 / 372 (14) ++++++
Регистрация: 04.06.2004
А кто-нибудь знает где в стандарте используется джоин временных таблиц?
__________________
-Ты в гномиков веришь?
-Нет.
-А они в тебя верят, смотри, не подведи их.
Старый 15.12.2011, 12:09   #24  
glibs is offline
glibs
Member
Сотрудники компании It Box
Most Valuable Professional
Лучший по профессии 2011
Лучший по профессии 2009
 
4,942 / 911 (40) +++++++
Регистрация: 10.06.2002
Адрес: I am from Kyiv, Ukraine. Now I am in Moscow. For private contacts: glibs@hotmail.com
Упомянутый выше глобальный поиск вас устроит в качестве примера?

\Classes\SysSearch.andResult()
__________________
С уважением,
glibs®
Старый 15.12.2011, 12:39   #25  
Pustik is offline
Pustik
Участник
 
807 / 372 (14) ++++++
Регистрация: 04.06.2004
Цитата:
Сообщение от glibs Посмотреть сообщение
Упомянутый выше глобальный поиск вас устроит в качестве примера?

\Classes\SysSearch.andResult()
Устроит . Меня больше интересовали места использования джоинов в каких-нибудь обработках, сопоставлениях, разносках. А точнее там, где непосредственно работают пользователи или там, где периодически запускается какая-нибудь мега-операция. Нам очень интересна производительность системы со взгляда пользователя. Может быть где-то что-то тормозит именно по причине, описанной в ветке, а мы и не знаем.
__________________
-Ты в гномиков веришь?
-Нет.
-А они в тебя верят, смотри, не подведи их.

Последний раз редактировалось Pustik; 15.12.2011 в 12:43.
Старый 15.12.2011, 12:43   #26  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
У кого есть доступ к 2012-й ?
Просьба проверить скорость джоина там.
Старый 15.12.2011, 12:57   #27  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
На самом деле временные (In Memory) таблицы не рекомендуется использовать в joins.
Да и вообще, их не рекомендуется использовать, если кол-во данных превышает 2000 Кб (или сколько там, забыл), когда их придется flush to disk. Пока они в памяти, все ОК. Диск, понятное дело, не самое быстрое устройство.

В 6.0 появились TempDB таблицы. Должно быть намного быстрее. Сейчас вашим джобиком замерю. Ограничение - они работают только для кода, который выполняется на сервере.
За это сообщение автора поблагодарили: lev (2).
Старый 15.12.2011, 13:04   #28  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,907 / 5717 (196) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
Цитата:
Сообщение от kashperuk Посмотреть сообщение
Да и вообще, их не рекомендуется использовать, если кол-во данных превышает 2000 Кб (или сколько там, забыл), когда их придется flush to disk.
128Кбит. Так что по моему их вообще не стоит использовать ни в каких случаях. При длине записи в 150 Байт (а это вполне типичное допущение), временная таблица начинает хандрить при 900 записях. Такой объем данных проще вообще в RecordSortedList запихать, чем париться с временной таблицей.
Старый 15.12.2011, 13:05   #29  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Вот результаты из 6ки:
Цитата:
Insert time: 0.28 seconds
(Join) Number of records iterated: 1001
(Join) Execution time: 6.63 seconds
(WhileSelect) Number of records iterated: 1001
(WhileSelect) Execution time: 0.05 seconds
Старый 15.12.2011, 13:07   #30  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,308 / 3540 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
А вот мои результаты (правда у меня диск подтормаживает с виртуалкой, но зато это тот же диск и тот же физический комп, на котором я прогонял джоб на АХ2009):
Название: 2012.PNG
Просмотров: 1662

Размер: 8.7 Кб
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 15.12.2011 в 13:11.
Старый 15.12.2011, 13:46   #31  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Результаты при использовании TempDB для маленькой выборки:
Цитата:
Insert time: 1.81 seconds
(Join) Number of records iterated: 1001
(Join) Execution time: 0.27 seconds
(WhileSelect) Number of records iterated: 1001
(WhileSelect) Execution time: 0.89 seconds
Как видим, join теперь работает быстрее, но InMemory временная таблица с while select была быстрее.


На большей выборке (40000) результаты следующие:
TempDB:
Insert time: 61.04 seconds
(Join) Number of records iterated: 40001
(Join) Execution time: 6.24 seconds
(WhileSelect) Number of records iterated: 40001
(WhileSelect) Execution time: 34.71 seconds

InMemory:
Висит до сих пор, уж не знаю, что делать. Минут 10 уже висит....

Кстати, на MSDN добавили довольно детальное описание обоих типов таблиц:
Temporary InMemory Tables
Temporary TempDB Tables
За это сообщение автора поблагодарили: Logger (8).
Старый 15.12.2011, 14:02   #32  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Решил проверить как в 2009-й работает джоин временной и постоянной таблички.
Для этого сделал постоянную табличку GRD_TmpAccountSum - близнеца времянки.
и попробовал позапускать джобик для разных комбинаций.

X++:
// [url=http://axforum.info/forums/showthread.php?p=264151#post264151]Временные таблицы и скорость работы[/url]
static void glibs_Job2(Args _args)
{
    TmpAccountSum tmpAccountSum1;
//    GRD_TmpAccountSum tmpAccountSum1;
    TmpAccountSum tmpAccountSum2;
//    GRD_TmpAccountSum tmpAccountSum2;
    Counter i;
    FreeText text;
    Counter startTime;

    #Define.cycles(1000)
    ;
    info(strFMT("isRunningOnServer() = %1", Global::isRunningOnServer()));
    info(strFMT("tmpAccountSum1.isTmp() = %1", tmpAccountSum1.isTmp()));
    info(strFMT("tmpAccountSum2.isTmp() = %1", tmpAccountSum2.isTmp()));
    delete_from tmpAccountSum1;
    delete_from tmpAccountSum2;
    
    startTime = WinAPI::getTickCount();
    for (i = 0; i <= #cycles; i++)
    {
        tmpAccountSum1.clear();
        tmpAccountSum2.clear();
        text = int2str(i);
        tmpAccountSum1.AccountNum = strrep("0", 20 - strlen(text)) + text;
        tmpAccountSum2.AccountNum = strrep("0", 20 - strlen(text)) + text;

        tmpAccountSum1.Balance01 = 999999 * 888888;
        tmpAccountSum2.Balance01 = 999999 * 888888;
        tmpAccountSum1.Balance02 = 999999 * 888888;
        tmpAccountSum2.Balance02 = 999999 * 888888;
        tmpAccountSum1.Balance03 = 999999 * 888888;
        tmpAccountSum2.Balance03 = 999999 * 888888;
        tmpAccountSum1.Balance04 = 999999 * 888888;
        tmpAccountSum2.Balance04 = 999999 * 888888;
        tmpAccountSum1.Balance05 = 999999 * 888888;
        tmpAccountSum2.Balance05 = 999999 * 888888;
        tmpAccountSum1.Balance06 = 999999 * 888888;
        tmpAccountSum2.Balance06 = 999999 * 888888;
        tmpAccountSum1.Balance07 = 999999 * 888888;
        tmpAccountSum2.Balance07 = 999999 * 888888;
        tmpAccountSum1.Balance10 = 999999 * 888888;
        tmpAccountSum2.Balance10 = 999999 * 888888;
        tmpAccountSum1.TaxCode = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum2.TaxCode = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum1.CurrencyCode = "XXX";
        tmpAccountSum2.CurrencyCode = "XXX";
        tmpAccountSum1.Posting = 1;
        tmpAccountSum2.Posting = 1;
        tmpAccountSum1.Dimension[1] = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum2.Dimension[1] = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum1.Dimension[2] = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum2.Dimension[2] = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum1.Dimension[3] = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum2.Dimension[3] = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum1.OperationsTax = 1;
        tmpAccountSum2.OperationsTax = 1;
        tmpAccountSum1.TransDate = today();
        tmpAccountSum2.TransDate = today();
        tmpAccountSum1.Txt = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +
        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +
        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +
        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum2.Txt = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +
        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +
        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +
        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum1.SortDate = today();
        tmpAccountSum2.SortDate = today();
        tmpAccountSum1.Balance01Cur = 999999 * 888888;
        tmpAccountSum2.Balance01Cur = 999999 * 888888;
        tmpAccountSum1.Qty01 = 999999 * 888888;
        tmpAccountSum2.Qty01 = 999999 * 888888;
        tmpAccountSum1.Qty02 = 999999 * 888888;
        tmpAccountSum2.Qty02 = 999999 * 888888;
        tmpAccountSum1.Qty03 = 999999 * 888888;
        tmpAccountSum2.Qty03 = 999999 * 888888;
        tmpAccountSum1.Voucher = "XXXXXXXXXXXXXXXXXXXX";
        tmpAccountSum2.Voucher = "XXXXXXXXXXXXXXXXXXXX";

        tmpAccountSum1.insert();
        tmpAccountSum2.insert();
    }
    info (strfmt("Prepare data took %1 seconds", (WinAPI::getTickCount() - startTime) / 1000));

    startTime = WinAPI::getTickCount();
    i = 0;
    while select tmpAccountSum1
    join tmpAccountSum2
    where tmpAccountSum1.AccountNum == tmpAccountSum2.AccountNum
    {
        text = tmpAccountSum1.Voucher + tmpAccountSum2.Voucher;
        i++;
    }
    info (strfmt("Join %1 loops", i));
    info (strfmt("Join %1 seconds", (WinAPI::getTickCount() - startTime) / 1000));

    startTime = WinAPI::getTickCount();
    i = 0;
    while select tmpAccountSum1
    {
        while select tmpAccountSum2
        where tmpAccountSum2.AccountNum == tmpAccountSum1.AccountNum
        {
            text = tmpAccountSum1.Voucher + tmpAccountSum2.Voucher;
            i++;
        }
    }
    info (strfmt("Sub while select %1 loops", i));
    info (strfmt("Sub while select %1 seconds", (WinAPI::getTickCount() - startTime) / 1000));

}

Цитата:
isRunningOnServer() = 1
tmpAccountSum1.isTmp() = true
tmpAccountSum2.isTmp() = true
Prepare data took 0,42 seconds
Join 1001 loops
Join 6,91 seconds
Sub while select 1001 loops
Sub while select 0,06 seconds


isRunningOnServer() = 1
tmpAccountSum1.isTmp() = false
tmpAccountSum2.isTmp() = true
Prepare data took 2,34 seconds
Join 1001 loops
Join 7,03 seconds
Sub while select 1001 loops
Sub while select 0,08 seconds

isRunningOnServer() = 1
tmpAccountSum1.isTmp() = true
tmpAccountSum2.isTmp() = false
Prepare data took 2,25 seconds
Join 1001 loops
Join 1,28 seconds
Sub while select 1001 loops
Sub while select 1,45 seconds

isRunningOnServer() = 1
tmpAccountSum1.isTmp() = false
tmpAccountSum2.isTmp() = false
Prepare data took 2,27 seconds
Join 1001 loops
Join 0,06 seconds
Sub while select 1001 loops
Sub while select 1,25 seconds
Старый 15.12.2011, 14:28   #33  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от fed Посмотреть сообщение
128Кбит. Так что по моему их вообще не стоит использовать ни в каких случаях. При длине записи в 150 Байт (а это вполне типичное допущение), временная таблица начинает хандрить при 900 записях. Такой объем данных проще вообще в RecordSortedList запихать, чем париться с временной таблицей.
В некоторых случаях без них трудно обойтись.
RecordSortedList - позволяет эффективно искать только по одному ключу.
А на времянке можно разных индексов понаделать и при поиске по индексированным поля скорость поиска не такая уж плохая.
Хотя все конечно определяется задачей, и требованиями по производительности.
Старый 15.12.2011, 15:24   #34  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от kashperuk Посмотреть сообщение
Да и вообще, их не рекомендуется использовать, если кол-во данных превышает 2000 Кб (или сколько там, забыл), когда их придется flush to disk. Пока они в памяти, все ОК. Диск, понятное дело, не самое быстрое устройство.
Иван, а почему бы не попробовать поднять этот предел ?
Как справедливо заметил fed - сейчас этот предел очень низкий. И не менялся с Ax3.0
За прошедшее время произошло много изменений в железках.
Памяти на серверах стало дофига и она дешева. А Аксапта между тем переехала на Юникод так что все текстовые данные распухли в 2 раза.

Может подбросить такую идею ядреным разработчикам ?
Старый 15.12.2011, 15:31   #35  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,907 / 5717 (196) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
С джойном временных и постоянных таблиц еще есть такая грабля: Допустим у тебя временная табличка из 30 записей (допустим с recId inventTrans). Ты джойнишь ее с inventTrans. Я бы ожидал, что система пробежиться по временной таблице и для каждой записи вытащит все относящиеся к ней записи на сервере. Но выяснилось что в каких-то случаях (а возможно и всегда) система сначала отправляет на сервер БД запрос для вытаскивания ВСЕЙ inventTrans, потом его сохраняет во временную таблицу на AOS и потом медленно и печально (поскольку индекса по временному inventTrans нету) джойнит его со временной таблицей.

Результаты можно наблюдать, например, при работе с функцией IM-Periodic->Release sales order picking. Умные разработчики насытили класс InventReleaseOrderPicking_Sales джойнами временной таблицы (с выбранными на форме recId) с SalesLine. После того как число строк заказов выросло до 500000, мои клиенты с удивлением заметили, гм, некоторое замедление функциональности. В итоге вся форма была переписана на использование set с recId вместо временной таблицы с recId.
За это сообщение автора поблагодарили: sukhanchik (10), Logger (10), lev (10), Kabardian (4).
Старый 15.12.2011, 15:39   #36  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Спасибо за инфу.

А вы точно уверены что все именно так и происходит ?
Откуда информация ?

Вот здесь
Временные таблицы и скорость работы
Цитата:
isRunningOnServer() = 1
tmpAccountSum1.isTmp() = true
tmpAccountSum2.isTmp() = false
Prepare data took 2,25 seconds
Join 1001 loops
Join 1,28 seconds
Sub while select 1001 loops
Sub while select 1,45 seconds
смоделирован этот случай. Только постоянная табличка по числу записей отличается InventTrans
Все же получилось не 7 секунд а 1,28. Хотя это почти одно и то же по порядку величины.
Старый 15.12.2011, 15:40   #37  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Что-то кстати у меня InMemory совсем плохи - то ли диск плохой, то ли их что-то испортили в 6.0

40000 я так и не дождался, а для 10000 результаты ниже:
Время заполнения данными: 8.24
Кол-во записей: 10001
Join: 655.03
Кол-во записей: 10001
While select: 0.48


Кто-то может попробовать у себя на АХ 2012?
Старый 15.12.2011, 16:11   #38  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,907 / 5717 (196) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
Цитата:
Сообщение от Logger Посмотреть сообщение
Спасибо за инфу.

А вы точно уверены что все именно так и происходит ?
Откуда информация ?
Ну я просто тупо трассировал SQL во время работы класса чтобы понять что тормозит. Оказалось что на сервер уходит запрос по всем строкам salesLines, после чего система надолго зависает. Конечно - все остальное это только предположение, но в нашем конкретном случае на RU6, по крайнее мере НЕКОТОРЫЕ запросы исполнялись таким образом...
Теги
временная таблица, оптимизация, полезное, производительность

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Как правильно именовать временные таблицы Владимир Максимов DAX: Программирование 22 17.05.2011 21:03
Временные таблицы и их временные файлы AraraT® DAX: Прочие вопросы 6 12.04.2010 00:39
Не страшно ли временные таблицы временно сделать постоянными? Gustav DAX: Программирование 11 09.02.2006 11:04
Временные таблицы vasiliy DAX: Программирование 6 09.11.2004 11:04
Временные таблицы в запросе Dron AKA andy DAX: Программирование 4 06.09.2002 12:14
Опции темы Поиск в этой теме
Поиск в этой теме:

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

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

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

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