|
![]() |
#1 |
Moderator
|
Ладно, поскольку дискуссия с Logger перешла в эту ветку, пожалуй продолжу здесь.
Во первых, в версии 2009 этот метод (adjustAmount) изрядно подоптимизировали. Во вторых - он ничего такого не делает ![]()
Однако есть одна загводка: Как известно, временные таблицы хранятся в памяти только если их размер не превышает 128 КБайт. Если размер превысил эту величину, то AOS выгружает их во временный файл, запросами и доступом к которому занимается сам AOS. А внутренний процессор запросов в AOS не быстрый и не оптимизировали его с прошлого столетия, вероятно он часто в fullscan скатывается ![]() Размер одной записи в tmpTaxWorkTrans в стандартной конфигурации, составляет 793 байта. Получается что где-то после 160 строк в заказе/закупке, данные из таблицы выгружаются на диск и начинают страшно тормозить в запросах. Если в новой версии (2012) tmpTaxWorkTrans переделали в SQL-ную временную таблицу, это должно заметно ускорить процесс. Также можно надеятся, что в 64битной версии сервера (а мне кажется 32битной и не будет) наконец-то отменили ограничение в 128 Кбайт под временную таблицу в памяти и теперь таблица будет храниться в памяти пока таковая имеется. Последний раз редактировалось fed; 03.05.2011 в 13:49. |
|
|
За это сообщение автора поблагодарили: Logger (5), ziva (2). |
![]() |
#2 |
Участник
|
Цитата:
Сообщение от fed
![]() ...
Однако есть одна загводка: Как известно, временные таблицы хранятся в памяти только если их размер не превышает 128 КБайт. Если размер превысил эту величину, то AOS выгружает их во временный файл, запросами и доступом к которому занимается сам AOS. А внутренний процессор запросов в AOS не быстрый и не оптимизировали его с прошлого столетия, вероятно он часто в fullscan скатывается ![]() Размер одной записи в tmpTaxWorkTrans в стандартной конфигурации, составляет 793 байта. Получается что где-то после 160 строк в заказе/закупке, данные из таблицы выгружаются на диск и начинают страшно тормозить в запросах. Если в новой версии (2012) tmpTaxWorkTrans переделали в SQL-ную временную таблицу, это должно заметно ускорить процесс. Также можно надеятся, что в 64битной версии сервера (а мне кажется 32битной и не будет) наконец-то отменили ограничение в 128 Кбайт под временную таблицу в памяти и теперь таблица будет храниться в памяти пока таковая имеется. Идея в том, чтобы заставить времянки создаваться в памяти. Например, можно завести виртуальный диск, реально живущий в памяти и прописать его в переменную окружения как темповую папку для пользователя, под которым работает сервер приложения. В таком случае файлы *.$$$, содержащие времянки будут реально жить в памяти и работать быстро. К сожалению, это не решило всех проблем. Если поиск во времянке делать по неиндексированному полю, то время улучшается примерно в 6-7 раз. Если по индексированному, то в 2 раза. (Т.е. индексы на больших времянках тоже существенно влияют на скорость) Также примерно в 2 раза ускоряется операция вставки. Мы ожидали бОльшего ускорения, поэтому на боевой базе не стали это применять. Тест проводили на примерно 100-200 тысячах записей буферов UnitConvert. Это составило примерно 50-100 мегабайт в $$$ файле на диске. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (5). |
![]() |
#3 |
Участник
|
Я тут в очередной раз занимался оптимизацией разноски розничных продаж и наткнулся еще на пару возможных улучшений.
1. Метод writeTaxAmount_W, который тут ранее оптимизировали вызывает в цикле метод CustVendInvoiceTrans.initFromTaxWorkTrans_RU(). Там выполняется неиндексируемый запрос к злосчастной темповухе TmpTaxWorkTrans. Единственный селективный фильтр там это номер лота InventTransId, но индекса по нему нету. Получается примерно такая трассировка В общем нужно добавить индекс и плюс пришлось еще поменять немного код на поиске. X++: if (SysCountryRegionCode::isLegalEntityInCountryRegion([#isoRU])) { //+ sergey.m 03.02.2022 FRE_20421639_001 if (!_sourceRecId) { select taxWorkTrans index hint InventTransIdx where taxWorkTrans.SourceTableId == _sourceTableId && taxWorkTrans.InventTransId == _inventTransId && taxWorkTrans.TaxDirection != TaxDirection::UseTax && taxWorkTrans.TaxOrigin != TaxOrigin::TaxReversed; } else { //- sergey.m 03.02.2022 FRE_20421639_001 select taxWorkTrans where taxWorkTrans.SourceTableId == _sourceTableId && ((_sourceRecId && taxWorkTrans.SourceRecId == _sourceRecId) || (! _sourceRecId && taxWorkTrans.InventTransId == _inventTransId)) && taxWorkTrans.TaxDirection != TaxDirection::UseTax && taxWorkTrans.TaxOrigin != TaxOrigin::TaxReversed; } 2. В классе Tax метод lineTaxAmount. В начале метода проверяется что в таблице есть записи немного экзотическим методом, считая их количество. Я поменял так, хотя можно было наверное вообще убрать запрос, меня пока и так устраивает. X++: if (this.taxParameters().TaxSpecifyLine) { if (this.taxParameters().TaxSpecifyLine) { //+ sergey.m 03.02.2022 FRE_20421639_001 //select count(RecId) from taxWorkTrans; select firstOnly RecId from taxWorkTrans; //- sergey.m 03.02.2022 FRE_20421639_001 if (taxWorkTrans.RecId > 0 && !this.useSubLedgerJournalLines()) { // Posting out of TmpTaxWorkTrans |
|
|
За это сообщение автора поблагодарили: trud (10), Logger (5). |
![]() |
#4 |
Участник
|
Цитата:
Я для 2009-й кое что правил - некие частные случаи с накладными расходами. Там проблема из-за нелинейной зависимости от числа строк при разноске. (где то на форуме была тема) Где возможно - 1. отключали корреспонденцию. 2. для больших документов (более 300 строк) вместо одной накладной делали кучку накладных по 40 строк. тем самым линеаризовали зависимость времени разноски от числа строк. - у нас были компании для управленческого учета где число накладных было неважно, главное итоговые показатели. Вот там такое было применимо. |
|
![]() |
#5 |
Участник
|
|
|
![]() |
#6 |
Участник
|
|
|
![]() |
#7 |
Участник
|
Да!
Да! Это прямо бросается в глаза. Перебор всего мапа со сравнением со значением на каждом шаге. Очень неэффективный поиск значения сделан. Видимо автор закладывался на то что раз операция в памяти то все будет быстро. Как бы не так! Там слишком много элементов в мапе на большом числе строк документа получается. Поскольку там не голый мап а класс обертка, то у меня была идея сделать в нем некий вспомогательный второй мап, который будет индексом к основному мапу и позволит не перебирать все элементы первого мапа для поиска значений. Но руки не дошли. |
|
![]() |
#8 |
Участник
|
Цитата:
Сообщение от Masel
![]() Я тут в очередной раз занимался оптимизацией разноски розничных продаж и наткнулся еще на пару возможных улучшений.
1. Метод writeTaxAmount_W, который тут ранее оптимизировали вызывает в цикле метод CustVendInvoiceTrans.initFromTaxWorkTrans_RU(). Там выполняется неиндексируемый запрос к злосчастной темповухе TmpTaxWorkTrans. Единственный селективный фильтр там это номер лота InventTransId, но индекса по нему нету. Получается примерно такая трассировка - на одну строку накладной одна запись в TmpTaxWorkTrans для RU, связь по номеру лота (по логике можно хранить и несколько записей, но кажется в этом случае особого профита по сравнению с индексом не будет) - получается можно до цикла по строкам получить map - ключ inventTransId, значение запись TmpTaxWorkTrans(в методе который собственно и формирует всю TmpTaxWorkTrans, т.е. дополнительных проходов не потребуется). - в цикле из мапа получать запись TmpTaxWorkTrans и ее отдавать в метод уже (в самом методе и чуть ниже придется поменять код, так что обрабатывать запись, а не курсор, но это не кажется сложным).
__________________
Sergey Nefedov |
|
![]() |
#9 |
Участник
|
Цитата:
Сообщение от SRF
![]() На уровне идеи (не факт конечно, что будет быстрее) - можно же вообще убрать запрос в этом месте к темповой табличке для RU функциональности(наверное и в общем случае можно, но будет чуть сложнее), я может конечно что то забываю или не учитываю, но идея такая :
- на одну строку накладной одна запись в TmpTaxWorkTrans для RU, связь по номеру лота (по логике можно хранить и несколько записей, но кажется в этом случае особого профита по сравнению с индексом не будет) - получается можно до цикла по строкам получить map - ключ inventTransId, значение запись TmpTaxWorkTrans(в методе который собственно и формирует всю TmpTaxWorkTrans, т.е. дополнительных проходов не потребуется). - в цикле из мапа получать запись TmpTaxWorkTrans и ее отдавать в метод уже (в самом методе и чуть ниже придется поменять код, так что обрабатывать запись, а не курсор, но это не кажется сложным). |
|
![]() |
#10 |
Участник
|
Цитата:
Сообщение от Masel
![]() Я тут в очередной раз занимался оптимизацией разноски розничных продаж и наткнулся еще на пару возможных улучшений.
<...> 2. В классе Tax метод lineTaxAmount. В начале метода проверяется что в таблице есть записи немного экзотическим методом, считая их количество. Я поменял так, хотя можно было наверное вообще убрать запрос, меня пока и так устраивает. X++: if (this.taxParameters().TaxSpecifyLine) { if (this.taxParameters().TaxSpecifyLine) { //+ sergey.m 03.02.2022 FRE_20421639_001 //select count(RecId) from taxWorkTrans; select firstOnly RecId from taxWorkTrans; //- sergey.m 03.02.2022 FRE_20421639_001 if (taxWorkTrans.RecId > 0 && !this.useSubLedgerJournalLines()) { // Posting out of TmpTaxWorkTrans \Classes\TaxPost\saveAndPost X++: public void saveAndPost(LedgerPostingController _ledgerPostingController, SelectableDataArea _companyToPost = curext()) { this.initLedgerPosting(_ledgerPostingController); //+ Abramov_ 27.05.2022 TSK0000280_08 //select count(RecId) from taxWorkTrans; select firstonly RecId from taxWorkTrans; //- Abramov_ 27.05.2022 TSK0000280_08 if (taxWorkTrans.RecId > 0 && !this.useSubLedgerJournalLines()) При создании строк накладной покупки в PurchInvoiceJournalCreate.createJournalLine() поле vendInvoiceTrans.LineAmount рассчитывается без учета экземпляра класса Tax, который был рассчитан на предыдущем шаге (в PurchInvoiceJournalCreate.initTotals()). Т.е. в initTotals мы формируем кэш проводок TaxUncommitted, и, если не передать Tax, мы делаем лишние запросы к тому же TaxUncommitted. X++: //+ Abramov_ 27.05.2022 TSK0000280_08 //vendInvoiceTrans.LineAmount = vendInvoiceInfoLine.lineAmountExclTax(vendInvoiceJour.InvoiceDate); vendInvoiceTrans.LineAmount = vendInvoiceInfoLine.lineAmountExclTax(vendInvoiceJour.InvoiceDate, this.parmTax()); //- Abramov_ 27.05.2022 TSK0000280_08 Еще мы провели эксперимент с переводом TmpTaxWorkTrans в TempDB (и обновлением существующей функциональности соответственно). Пришли к выводу, что без существенного рефакторинга кода от версии TmpTaxWorkTrans в TempDB толку нет, т.к. производительность расчета налогов упала ровно в два раза. Последний раз редактировалось DarkSpirit22; 27.05.2022 в 11:29. |
|
|
За это сообщение автора поблагодарили: Logger (5). |
Теги |
faq, tax, налоги, оптимизация, производительность |
|
![]() |
||||
Тема | Ответов | |||
Вызов метода базового класса | 15 | |||
jerry-dynamics: tax codes | 0 | |||
Вызов класса из другого класса | 9 | |||
передача курсора в два класса | 3 | |||
Запустить метод класса | 2 |
|