15.12.2011, 02:12 | #21 |
Участник
|
|
|
15.12.2011, 02:20 | #22 |
Member
|
Мои исследования начались с попыток "прокачать" движок глобального поиска (реальная прикладная задача).
Похоже что когда количество данных у меня достигнет определенного предела — вместо временных табличек таки придется написать что-то другое. Либо в 6.0 что-то изменится. Я слышал про планы переноса временных таблиц в SQL СУБД. Посмотрим... Если припрет — отпишу чем все закончилось. Вообще... либо постоянные таблицы, либо мапы... Но на таких объемах запись в постоянные таблицы тоже не будет быстрой. Особенно если их еще и индексами снабдить.
__________________
С уважением, glibs® |
|
15.12.2011, 10:05 | #23 |
Участник
|
А кто-нибудь знает где в стандарте используется джоин временных таблиц?
__________________
-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. |
|
15.12.2011, 12:09 | #24 |
Member
|
Упомянутый выше глобальный поиск вас устроит в качестве примера?
\Classes\SysSearch.andResult()
__________________
С уважением, glibs® |
|
15.12.2011, 12:39 | #25 |
Участник
|
Устроит . Меня больше интересовали места использования джоинов в каких-нибудь обработках, сопоставлениях, разносках. А точнее там, где непосредственно работают пользователи или там, где периодически запускается какая-нибудь мега-операция. Нам очень интересна производительность системы со взгляда пользователя. Может быть где-то что-то тормозит именно по причине, описанной в ветке, а мы и не знаем.
__________________
-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. Последний раз редактировалось Pustik; 15.12.2011 в 12:43. |
|
15.12.2011, 12:43 | #26 |
Участник
|
У кого есть доступ к 2012-й ?
Просьба проверить скорость джоина там. |
|
15.12.2011, 12:57 | #27 |
Участник
|
На самом деле временные (In Memory) таблицы не рекомендуется использовать в joins.
Да и вообще, их не рекомендуется использовать, если кол-во данных превышает 2000 Кб (или сколько там, забыл), когда их придется flush to disk. Пока они в памяти, все ОК. Диск, понятное дело, не самое быстрое устройство. В 6.0 появились TempDB таблицы. Должно быть намного быстрее. Сейчас вашим джобиком замерю. Ограничение - они работают только для кода, который выполняется на сервере. |
|
|
За это сообщение автора поблагодарили: lev (2). |
15.12.2011, 13:04 | #28 |
Moderator
|
128Кбит. Так что по моему их вообще не стоит использовать ни в каких случаях. При длине записи в 150 Байт (а это вполне типичное допущение), временная таблица начинает хандрить при 900 записях. Такой объем данных проще вообще в RecordSortedList запихать, чем париться с временной таблицей.
|
|
15.12.2011, 13:05 | #29 |
Участник
|
Вот результаты из 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 |
Administrator
|
А вот мои результаты (правда у меня диск подтормаживает с виртуалкой, но зато это тот же диск и тот же физический комп, на котором я прогонял джоб на АХ2009):
__________________
Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 15.12.2011 в 13:11. |
|
15.12.2011, 13:46 | #31 |
Участник
|
Результаты при использовании 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 На большей выборке (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 |
Участник
|
Решил проверить как в 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 |
Участник
|
Цитата:
Сообщение от fed
128Кбит. Так что по моему их вообще не стоит использовать ни в каких случаях. При длине записи в 150 Байт (а это вполне типичное допущение), временная таблица начинает хандрить при 900 записях. Такой объем данных проще вообще в RecordSortedList запихать, чем париться с временной таблицей.
RecordSortedList - позволяет эффективно искать только по одному ключу. А на времянке можно разных индексов понаделать и при поиске по индексированным поля скорость поиска не такая уж плохая. Хотя все конечно определяется задачей, и требованиями по производительности. |
|
15.12.2011, 15:24 | #34 |
Участник
|
Цитата:
Как справедливо заметил fed - сейчас этот предел очень низкий. И не менялся с Ax3.0 За прошедшее время произошло много изменений в железках. Памяти на серверах стало дофига и она дешева. А Аксапта между тем переехала на Юникод так что все текстовые данные распухли в 2 раза. Может подбросить такую идею ядреным разработчикам ? |
|
15.12.2011, 15:31 | #35 |
Moderator
|
С джойном временных и постоянных таблиц еще есть такая грабля: Допустим у тебя временная табличка из 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 |
Участник
|
Спасибо за инфу.
А вы точно уверены что все именно так и происходит ? Откуда информация ? Вот здесь Временные таблицы и скорость работы Цитата:
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 Все же получилось не 7 секунд а 1,28. Хотя это почти одно и то же по порядку величины. |
|
15.12.2011, 15:40 | #37 |
Участник
|
Что-то кстати у меня InMemory совсем плохи - то ли диск плохой, то ли их что-то испортили в 6.0
40000 я так и не дождался, а для 10000 результаты ниже: Время заполнения данными: 8.24 Кол-во записей: 10001 Join: 655.03 Кол-во записей: 10001 While select: 0.48 Кто-то может попробовать у себя на АХ 2012? |
|
15.12.2011, 16:11 | #38 |
Moderator
|
Ну я просто тупо трассировал SQL во время работы класса чтобы понять что тормозит. Оказалось что на сервер уходит запрос по всем строкам salesLines, после чего система надолго зависает. Конечно - все остальное это только предположение, но в нашем конкретном случае на RU6, по крайнее мере НЕКОТОРЫЕ запросы исполнялись таким образом...
|
|