17.04.2007, 18:01 | #1 |
Участник
|
aEremenko: Update_RecordSet
Источник: http://blogs.msdn.com/aeremenk/archi...7/2161619.aspx
============== Update_RecordSet относится к многострочным функциям, позволяющим производить обновление либо вставку нескольких записей за одну операцию. Такие операции существенно уменьшают число запросов к базе данных и позволяют улучшить производительность операций. Судя по сообщениям коллег, работающих в центре разработки, в 5.0 (а может и раньше, если успеют) планируется использование объединений (inner и outer) в update_RecordSet. Например, возьмем код: X++: while select * from custCollectionLetterTrans where custCollectionLetterTrans.CollectionLetterNum == this.CollectionLetterNum && custCollectionLetterTrans.AccountNum == this.AccountNum && custCollectionLetterTrans.CollectionLetterIssued { custTrans = CustTrans::find(custCollectionLetterTrans.CustTransId, true); custTrans.CollectionLetterCode = custCollectionLetterTrans.CollectionLetterCode; custTrans.update(); } X++: update_recordset custTrans setting CollectionLetterCode = custCollectionLetterTrans.CollectionLetterCode join custCollectionLetterTrans where custCollectionLetterTrans.CollectionLetterNum == this.CollectionLetterNum && custCollectionLetterTrans.AccountNum == this.AccountNum && custCollectionLetterTrans.CollectionLetterIssued && custTrans.RecId == custCollectionLetterTrans.CustTransId; Источник: http://blogs.msdn.com/aeremenk/archi...7/2161619.aspx
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору. |
|
|
За это сообщение автора поблагодарили: Recoilme (5). |
17.04.2007, 21:01 | #2 |
Участник
|
Цитата:
1. в обрабатываемой таблице нет переопределенных методов insert, update, delete соответственно 2. обрабатываемая таблица не включена в RLS 3. обрабатываемая таблица не содержит deleteAction (для удаления) Да, можно отключить эти факторы при помощи skip-методов. Но отключение переопределенных методов чревато тем, что логическая целостность базы нарушится. Подробнее см хелп, ключевая фраза "What prevents fast SQL operations?" Кроме того, подобные операции может быть и повышают производительность, но гарантировано уменьшают наглядность и юзабилити. Обычно при длительной обработке данных показывают прогресс-бар, который показывает сколько процентов осталось. Групповые операции ничего не показывают. Если групповая операция выполняется несколько минут, то вы не знаете: повисла она, заблокирована или таки выполняется. И кроме того, групповые операции блокируют ВСЕ обрабатываемые записи за один раз. А обработка каждой записи, при правильном написании, блокирует только обрабатываемую запись. См. aEremenko: Ресурс заблокирован, ждите... Ну, и напоследок, групповые операции не позволяют работать с критериями из query. Что напрочь лишает их полезность, если пользователь может задавать критерии со спец-символами http://axapta.mazzy.ru/lib/search/ В общем, групповые операции дело хорошее. Но у них тоже есть минусы. Цитата:
Сообщение от Blog bot
Например, возьмем код:
X++: while select * from custCollectionLetterTrans where custCollectionLetterTrans.CollectionLetterNum == this.CollectionLetterNum && custCollectionLetterTrans.AccountNum == this.AccountNum && custCollectionLetterTrans.CollectionLetterIssued { custTrans = CustTrans::find(custCollectionLetterTrans.CustTransId, true); custTrans.CollectionLetterCode = custCollectionLetterTrans.CollectionLetterCode; custTrans.update(); } Более правильный код: X++: SysProgressOperation progress; ; select count(recid) from custCollectionLetterTrans where custCollectionLetterTrans.CollectionLetterNum == this.CollectionLetterNum && custCollectionLetterTrans.AccountNum == this.AccountNum && custCollectionLetterTrans.CollectionLetterIssued; progress = SysProgressOperation::newGeneral('','',custCollectionLetterTrans.recid); while select * from custCollectionLetterTrans where custCollectionLetterTrans.CollectionLetterNum == this.CollectionLetterNum && custCollectionLetterTrans.AccountNum == this.AccountNum && custCollectionLetterTrans.CollectionLetterIssued { ttsbegin; custTrans = CustTrans::find(custCollectionLetterTrans.CustTransId, true); custTrans.CollectionLetterCode = custCollectionLetterTrans.CollectionLetterCode; custTrans.update(); ttscommit; progress.inccount(); } X++: SysProgressOperation progress; Query q; QueryBuildDataSource = qbds; QueryRun qr; ; q = new Query(queryStr(mySupercustCollectionLetterTransQuery)); qbds = q.datasourcetable(tablenum(custCollectionLetterTrans)); SysQuery::findOrCreateRange(qbds,fieldnum(custCollectionLetterTrans,CollectionLetterNum ).value(this.CollectionLetterNum); SysQuery::findOrCreateRange(qbds,fieldnum(custCollectionLetterTrans,AccountNum).value(this.AccountNum ); SysQuery::findOrCreateRange(qbds,fieldnum(custCollectionLetterTrans,CollectionLetterIssued).value(SysQuery::notEmptyString()); qr = new QueryRun(q); progress = SysProgressOperation::newGeneral('','',SysQuery::CountTotal(qr)); while( qr.next() ) { custCollectionLetterTrans = qr.getTable(tablenum(custCollectionLetterTrans)); ttsbegin; custTrans = CustTrans::find(custCollectionLetterTrans.CustTransId, true); custTrans.CollectionLetterCode = custCollectionLetterTrans.CollectionLetterCode; custTrans.update(); ttscommit; progress.inccount(); } 1. отделить запрос и процесс его оптимизации от программирования. 2. позволяет работать с пользовательскими критериями 3. полностью совместим со всей функциональностью форм и отчетов 4. полностью совместим с пакетной обработкой 5. информирует пользователя о ходе выполнения. Поэтому... Если уж начали двигаться в сторону групповых операций... Если это возможно.... Нужен не update_recordset, а дополнительный режим групповой обработки для Query. |
|
|
За это сообщение автора поблагодарили: Recoilme (-2), kashperuk (3), oip (9). |
18.04.2007, 14:06 | #3 |
Участник
|
Цитата:
Сообщение от Blog bot
Источник: [url]Update_RecordSet относится к многострочным функциям, позволяющим производить обновление либо вставку нескольких записей за одну операцию.
В Axapta, класс Common, родитель для классов таблиц предоставляет мощный механизм OBJECT-RELATIONAL MAPPING (ORM), что является ключевой особенностью объектого подхода в моделировании и разработке приложений. Реляционные подходы в объектной системе только испортят наглядность. |
|
18.04.2007, 14:49 | #4 |
NavAx
|
Цитата:
Сообщение от mazzy
Это отвратительный код, за который надо штрафовать программиста и снижать его зарплату. Надеюсь, что этот код упрощен только для демонстрационных целей
Более правильный код: ..... Этот код позволяет: 1. отделить запрос и процесс его оптимизации от программирования. 2. позволяет работать с пользовательскими критериями 3. полностью совместим со всей функциональностью форм и отчетов 4. полностью совместим с пакетной обработкой 5. информирует пользователя о ходе выполнения. 1.) Ваш код замедляет работу из-за множества мелких транзакций. 2.) Визуализация тоже стоит времени - на длительных операциях замечал разницу, если не ошибаюсь, в 30%.
__________________
С уважением, Игорь Ласийчук. Последний раз редактировалось Garic; 18.04.2007 в 14:52. |
|
|
За это сообщение автора поблагодарили: Recoilme (5). |
18.04.2007, 15:35 | #5 |
Участник
|
В работе операций update_recordset есть некоторые ньюансы которые дают сложноотлавливаемые баги.
На одной из версий Аксапты (уже и не помню какой) применение двух последовательных update_recordset давало некорректный результат. Осталось предположение, что отправив запрос на обновление на sqlсервер система продолжила выполнение последующего кода, не дожидаясь полного выполнения запроса. Как результат, следующий update_recordset, использующий результаты предыдущего давал некорректные результаты. Поборолось обрамлением каждого update_recordset в отдельных ttsbegin/ttscommit. Но осадочек остался... |
|
18.04.2007, 16:05 | #6 |
злыдень
|
У каждого подхода есть свои плюсы минусы. Можно 30 минут показывать пользователю "градусник", а можно за пару минут выполнить туже операцию, но без градусника.
И каждый метод может дать "неожиданные" результаты, особенно если не понимать как они работают. Я лишь присоединюсь к первоначальному посту А.Еременко: Супер!
__________________
Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/ |
|
18.04.2007, 21:23 | #7 |
Участник
|
Цитата:
Приведенный мной код замедляет работу ТОЛЬКО одного пользователя. НО приведенный мной код ускоряет работу НЕСКОЛЬКИХ одновременно работающих пользователей. Из-за снижения вероятности блокировок. За подробностями обращайтесь к совету Еременко. Цитата:
Пользуйтесь стандартным классом SysOperationProgress. Разберитесь как и когда он обновляется и при каких условиях. Обсуждение этого класса наверное оффтопик в этой ветке. |
|
18.04.2007, 21:25 | #8 |
Участник
|
Можно пример?
|
|
19.04.2007, 06:22 | #9 |
сибиряк
|
Особенно чудные результаты дает этот класс при работе с несколькими компаниями.
__________________
С уважением, Вячеслав. |
|
19.04.2007, 08:05 | #10 |
Участник
|
Цитата:
Здесь давайте вернемся к групповым операциям в Аксапте? |
|
19.04.2007, 09:01 | #11 |
злыдень
|
Цитата:
Сообщение от mazzy
Более правильный код:
X++: SysProgressOperation progress; ; select count(recid) from custCollectionLetterTrans where custCollectionLetterTrans.CollectionLetterNum == this.CollectionLetterNum && custCollectionLetterTrans.AccountNum == this.AccountNum && custCollectionLetterTrans.CollectionLetterIssued; progress = SysProgressOperation::newGeneral('','',custCollectionLetterTrans.recid); while select * from custCollectionLetterTrans where custCollectionLetterTrans.CollectionLetterNum == this.CollectionLetterNum && custCollectionLetterTrans.AccountNum == this.AccountNum && custCollectionLetterTrans.CollectionLetterIssued { ttsbegin; custTrans = CustTrans::find(custCollectionLetterTrans.CustTransId, true); custTrans.CollectionLetterCode = custCollectionLetterTrans.CollectionLetterCode; custTrans.update(); ttscommit; progress.inccount(); } ... Представьте простую ситуацию, Вы разносите накладную из 100 строк. каждая строка обрабатывается в отдельной транзакции. На строке 87 возникает исключительная ситуация , товара недостаточно на складе, а предыдущие 86 строк уже списали товар.... Помедитируйте на тему зачем вообще нужны транзакции, как они работают и что такое целостность данных Буквально пару дней назад думал убью долго и подробно объяснял 3 одинэсникам почему, например, импорт документа из аксапты надо облачать в транзакзию, а не обрабатывать построчно как они привыкли. То ли это 1с разрушает моск, то ли просто так совпало
__________________
Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/ |
|
19.04.2007, 09:48 | #12 |
Участник
|
Recoilme, вы понимаете разницу между "ЭТОТ код" и "ПРЕДСТАВЬТЕ простую ситуацию".
Цитата:
Цитата:
Импорт документа в одной транзакции Но, скорее всего, не должно быть облачающей транзакции для импорта всех документов. Речь об этом, а не о строчках. Строчки естественно должны импортироваться в "облачающей" транзакции. Как то да... Берегите себя. |
|
19.04.2007, 09:58 | #13 |
NavAx
|
Цитата:
Если ожидается что транзакция будет слишком большой что чревато блокировками да и просто тормозит работу, надо стараться разбить её, в многих случаях это возможно. Можно делать ttscommit/ttsbegin например после каждых 500 строк. Но за маленькие транзакции я бью по рукам Чтобы не быть голословным - провёл тест (по 5 тестов на каждый вариант) на табличке inventTrans (14 тыс. записей). Добавил в неё текстовое поле 10 - в него пишу timenow. В случае одной транзакции - 34,8 сек. (100%) В случае маленьких транзакций с прогрессбаром - 68,3 сек (196%) В случае маленьких транзакций без прогрессбара - 65,2 сек (187%) Версия Axapta - 4.0 SP1 Как показал тест, действительно немного он тратит, зря я его так. Хотя может это в четвёрке стало быстрее. Мне запомнилась цифра в 30%, надо бы проверить на трёшке.
__________________
С уважением, Игорь Ласийчук. |
|
19.04.2007, 10:12 | #14 |
Участник
|
Да, например.
А вот это зря. Цитата:
Сообщение от Garic
Чтобы не быть голословным - провёл тест (по 5 тестов на каждый вариант) на табличке inventTrans (14 тыс. записей). Добавил в неё текстовое поле 10 - в него пишу timenow.
В случае одной транзакции - 34,8 сек. (100%) В случае маленьких транзакций с прогрессбаром - 68,3 сек (196%) В случае маленьких транзакций без прогрессбара - 65,2 сек (187%) Вы оптимизируете работу ОДНОГО пользователя. Попробуйте запустить хотя бы 10-20, а лучше 50-100 пользователей, которые работают с InventTrans, пишут и читают один и тот же набор данных. Оцените производительность больших и маленьких транзакций для МНОГОПОЛЬЗОВАТЕЛЬСКОЙ системы. Про прогресс бар пожалуйста сюда Какие проблемы у SysOperationProgress? Здесь предлагаю сосредоточиться на больших и маленьких транзакциях, групповых и негрупповых обработках данных. |
|
19.04.2007, 10:15 | #15 |
Участник
|
Кстати, 14 тыс - это небольшое число. Все записи, скорее всего, помещаются в кэш сервера.
О влиянии кэша см. http://axapta.mazzy.ru/lib/axapta_itanium/ Но даже на таком маленьком числе записей разница в многопользовательском тесет будет заметна. Пожалуйста, не надо из Аксапты делать однопользовательскую ЕРП. Пожалуйста, тестируйте для многих пользователей. |
|
19.04.2007, 15:05 | #16 |
NavAx
|
Был исходный код, вы назвали его ужасным и предложили свой, мне он не понравился.
Я не говорил что надо всё обрабатывать в одной транзакции. Я говорил что не надо так однозначно отзываться о коде. В каких-то случаях будет правильным первый вариант, в каких-то ваш. Но для длительных операций, не стоит делать такие маленькие транзакции как в вашем примере. Если уж делать, то объединять в одну транзакцию несколько итераций (например 500). Ну а блокировки - в четвёрке вроде с ними легче стало.
__________________
С уважением, Игорь Ласийчук. |
|
19.04.2007, 16:47 | #17 |
Участник
|
Цитата:
Я продолжаю настаивать на том, что для многопользовательской системы транзакции надо делать как можно меньше. Пожалуйста, читайте совет Еременко aEremenko: Ресурс заблокирован, ждите... Если не верите, то проведите многопользовательский тест. Пожалуйста. Результаты тестирования в однопользовательском режиме не являются критериями правильности для транзакций (транзакции в однопользовательском режиме вообще не нужны). |
|
Теги |
recordset, update_recordset, ax2009 |
|
|