03.07.2013, 11:07 | #1 |
Участник
|
Удаление записей с собираемым условием как в query
Продолжая тему т.н. "динамического программирования" (подходящий правильный термин ищем здесь)
Если нужно сделать выборку по программно-собираемому условию, то все знаю, что надо использовать классы QueryRun, Query, QueryBuildRange и т.д. А если нужно удалить записи по динамическому условию. Я не знаю такого механизма, ни когда его не встречал. Точнее есть такие механизмы, но они не такие красивые как Query. 1. Один такой механизм применяется в браузере таблиц 2. Еще можно сформировать и отправить прямой запрос на SQL с помощью всяких коннекторов. А хочется чего то правильного в рамках общей логики системы... |
|
03.07.2013, 11:22 | #2 |
Участник
|
в чем проблема то? выбирайте записи и удаляйте
|
|
03.07.2013, 11:31 | #3 |
Участник
|
|
|
03.07.2013, 11:38 | #4 |
Участник
|
X++: while (queryRun.next()) { salesTable = queryRun.get(tableNum(SalesTable)); ttsbegin; updSalesTable = SalesTable::find(salesTable.SalesId, true); if (updSalesTable.RecId) updSalesTable.delete(); ttscommit; } |
|
|
За это сообщение автора поблагодарили: Мартынов Дмитрий (1). |
03.07.2013, 12:09 | #5 |
Участник
|
Цитата:
А без циклов что нибудь есть? Мы же можем написать X++: delete_from salesTable where ... X++: salesTable.skipEvents(true); salesTable.skipDataMethods(true); Хочется чего то такого (следующий код является фантазией по этому во избежании путаницы ставлю тег PHP++): PHP код:
|
|
03.07.2013, 13:35 | #6 |
Участник
|
Если предположить, что за раз будет удаляться не очень много записей - в пределах 10 тысяч, допустим (иначе транзакционный лог раздуется, и транзакция удаления записей будет достаточно долго отрабатывать) - то можно использовать такой подход: создать Query для выбора RecId удаляемых записей, при этом записи фильтровать по произвольным параметризируемым критериям, затем полученные RecId записать во вспомогательную таблицу (по аналогии с тем, как работает класс RecordReferenceList_RU) и в delete_from приджойнить ее к таблице, записи из которой удаляются.
|
|
|
За это сообщение автора поблагодарили: Мартынов Дмитрий (1). |
03.07.2013, 14:13 | #7 |
Участник
|
Не совсем так.
ты говоришь об ОДНОМ клиенте. А Аксапта - сетевая система. Обрати внимание на вложенную транзакцию, которая присутствует в предлагаемом тебе примере. В цикле с маленькими транзакциями блокировки не эскалируются. Время, на которое блокируется каждая запись минимально. delete_from будет делаться в одной транзакции. Следовательно велика вероятность эскалации блокировок. Кроме того, все затрагиваемые записи будут заблокированы до окончания транакции. Следовательно общая производительность скорее всего будет ниже из-за блокировок, а вероятность deadlock'ов сильно возрастает. =============== Где-то в книжках по аксапте читал, что когда вводили групповые операции delete_from, updaterecordset и insertrecordset крепко думали об этом. Суть - в операторах за быстродействие полностью отвечает программист. И это его непосредственная задача думать о производительности. Query, в отличие от оператора, может корректироваться пользователем. Поэтому, христос его знает, что может ввести туда пользователь... и условия по полям без индекса, и дополнительные join... поэтому вводить такую фичу в Query не стали. |
|
|
За это сообщение автора поблагодарили: Мартынов Дмитрий (1). |
03.07.2013, 15:10 | #8 |
Участник
|
Удаление - это очень опасная операция. Если вы для SalesTable поставите skipDataMethods(true), то у вас останутся строки заказов без шапки и останутся складские проводки. Я за свою жизнь наверное ни разу не использовал skipDataMethods(true)
skipDataMethods(true) можно использовать только в случаях, когда требуется администрирование данных, а не обычная ежедневная работа в штатном режиме. Но для администрирования данных лучше уж работать напрямую с SQL. |
|
03.07.2013, 17:01 | #9 |
Moderator
|
Я пожалуй добавлю еще одну технику из этой же оперы. Допустим нам надо сделать обновление большого числа записей по хитрому алкогоритму. Поскольку хитрый алкогоритм в виде update_recordset не переписать, я иногда, когда нужна максимальная производительность любой ценой, делаю так:
1. Создаю таблицу с полями updateId (GUID), Key (может быть refRecId или salesId или что-то подобное), и полями newVal1,newVal2,newVal3 и тп 2. Далее, в цикле, вместо обновления записей основной таблицы, через RecordInsertList вставляю новые записи, засовывая в ее поля ключи основной таблицы и значимые поля с новыми значениями. 3. Затем, после recordInsertList.insertDatabase() пишу X++: update_recordset mainTable setting field1=tempTable.NewValue1,field2=tempTable.NewValue2 join tmpValuesTable where tmpValuesTable.updateId==myGuid && tmpValuesTable.key=mainTable.key Последний раз редактировалось fed; 03.07.2013 в 17:12. Причина: Стиль |
|
|
За это сообщение автора поблагодарили: Мартынов Дмитрий (1), coolibin (2). |
03.07.2013, 17:37 | #10 |
Участник
|
|
|
03.07.2013, 17:48 | #11 |
Moderator
|
|
|
|
За это сообщение автора поблагодарили: mazzy (2). |