|
18.08.2016, 09:33 | #1 |
Участник
|
Ax2009, сбросить кеш recid SystemSequences
Ситуация следующая:
Через SQL-запрос (запускаемый из X++) вставляю большое количество записей в таблицу. Таблицу SystemSequences в том же запросе обновляю. Однако при дальнейшей попытке вставить в эту же таблицу запись уже в X++ получаю конфликт recid. При проверке обнаруживаю, что SystemSequence.ReserveValues() для этой таблицы возвращает значение меньшее, чем значение в таблице SystemSequences. Насколько я знаю, в каждой сессии RecId для таблицы выделяются пачками, которая кешируется в клиенте. И подозреваю, что следующий RecId после моих манипуляций с данными, выбирается все ещё из старого кеша, а не берется новая пачка значений из таблицы SystemSequences. Вопрос: как в данной ситуации сбросить кэш выбранных RecId для того чтобы спокойно продолжить вставку в таблицу без конфликтов? |
|
18.08.2016, 09:57 | #3 |
Участник
|
Все бы хорошо, но в моем Ax2009 в systemSequence в Ax2009 нет метода flushCache()
|
|
18.08.2016, 10:05 | #4 |
Moderator
|
В идеале - перезапустить бы АОС после обновления SystemSequences.
__________________
Андрей. |
|
18.08.2016, 10:13 | #5 |
Участник
|
О да, было бы здорово, вот только у меня все это происходит внутри даже не одной пользовательской сессии, а одной непрерывной операции.
|
|
18.08.2016, 10:18 | #6 |
Участник
|
Путем эксперимента выяснилось, что, похоже, нужный эффект дает следующая комбинация:
1) обновляем значение в таблице SystemSequences 2) делаем suspendRecIds для нужной таблицы 3) делаем removeRecIdSuspension для неё По крайней мере на моем конкретном примере это проблему решило, если это не случайное совпадение |
|
01.02.2017, 13:56 | #7 |
Участник
|
Цитата:
Сообщение от Pandasama
Путем эксперимента выяснилось, что, похоже, нужный эффект дает следующая комбинация:
1) обновляем значение в таблице SystemSequences 2) делаем suspendRecIds для нужной таблицы 3) делаем removeRecIdSuspension для неё По крайней мере на моем конкретном примере это проблему решило, если это не случайное совпадение Только диагноз теперь хуже: при попытке выделить новые RecId для таблицы, для которой SystemSequence изменен в запросе - через N значений выделенных (руками выделенных или вставкой - не важно) - получаю мертвую блокировку на таблице SystemSequence. Ну и значения выделяются меньше, чем те что в SystemSequence прописаны - из каких-то старых кэшей, видимо |
|
18.08.2016, 10:18 | #8 |
Участник
|
А что именно вы делаете в запросе?
ИМХО, чистый SQL лучше использовать для экзотической SELECT-выборки. остальные операции следует выполнять штатными средствами. Если вы хотите вставить пачку записей, чем плох RecordInsertList?
__________________
// no comments |
|
18.08.2016, 10:25 | #9 |
Участник
|
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы |
|
18.08.2016, 10:44 | #10 |
Боец
|
Цитата:
Сообщение от Pandasama
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы - если версия по-старше, то пара suspendRecIds + removeRecIdSuspension обязательна. - Обновлять же самому SystemSequence допускается только в случаях Application Maintance Последний раз редактировалось DSPIC; 18.08.2016 в 10:47. |
|
|
За это сообщение автора поблагодарили: dech (3). |
18.08.2016, 13:02 | #11 |
Участник
|
Цитата:
Сообщение от Pandasama
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы Вы уверены, что skipDataMethods(), skipDatabaseLog() не помогают?
__________________
// no comments |
|
18.08.2016, 13:21 | #12 |
Участник
|
Нет возможности средствами X++ сделать insert_recordset - слишком сложные условия.
В SQL это выполняется (иногда через дополнительные промежуточные временные таблицы). А в X++ это вырождается в цикл получения записей + вставка записей через InsertRecordList В итоге SQL на порядки быстрее Впрочем, речь не об о том, нужно ли писать в базу через SQL, а о том как сбросить кэш recid в 2009й версии. |
|
18.08.2016, 13:31 | #13 |
Участник
|
Цитата:
Сообщение от Pandasama
Нет возможности средствами X++ сделать insert_recordset - слишком сложные условия.
В SQL это выполняется (иногда через дополнительные промежуточные временные таблицы). А в X++ это вырождается в цикл получения записей + вставка записей через InsertRecordList В итоге SQL на порядки быстрее Впрочем, речь не об о том, нужно ли писать в базу через SQL, а о том как сбросить кэш recid в 2009й версии. По сабжу посмотрите здесь пример: https://msdn.microsoft.com/en-us/library/aa638594.aspx
__________________
// no comments |
|
18.08.2016, 18:03 | #14 |
Участник
|
Да при чем здесь запрос! Основной тормоз Вы поимеете на закачке этой кучи записей на AOS и последующий возврат обратно на SQL. А время выполнения собственно запроса уже становится не критичным
Если речь идет о вставке миллионов записей, которые формируются непосредственно в базе SQL, то прокачка их через AOS для вставки средствами Axapta - крайне медленная операция.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
19.08.2016, 03:17 | #15 |
Enjoy!
|
AX 2009, 2012:
X++: systemSequence seq = new SystemSequence(); if (seq) { // Выделяем 20 записей SalesTable seq.reserveValues(20, tablenum(SalesTable)); // Приостановить автоматическое распределение RECID seq.suspendRecIds(tablenum(SalesTable)); // Вручную генерим RecId в выбранном диапазоне, если необходимо // Снять остановку распределения seq.removeRecIdSuspension(); } X++: systemSequence::flushCache(); Последний раз редактировалось iCloud; 19.08.2016 в 03:20. |
|
|
За это сообщение автора поблагодарили: Владимир Максимов (2). |
01.02.2017, 17:33 | #16 |
Участник
|
Не обновляйте вручную таблицу SystemSequences. Только через класс SystemSequences в среде Axapta
Я делаю так: 1. Средствами SQL определяю количество записей, которые будут вставлены 2. В среде Axapta через класс SystemSequences резервирую нужное количество значений 3. Средствами SQL выполняю создание записей и формирование RecId Вот фрагмент для резервирования RecId в Ax4.0 X++: // Резервирование значений RecId для создания записей средствами SQL // Возвращает первое зарезервированное значение RecId protected int64 runReserveRecId(TableId _tableId, int64 _reservedRecords) { systemSequence systemSequence; Int64 beginRecId; ; systemSequence = new systemSequence(); // Приостановить автоматическое распределение RecId для указанной таблицы systemSequence.suspendRecIds(_tableId); // Выделяем нужное количество записей beginRecId = systemSequence.reserveValues(_reservedRecords,_tableId); // Снять остановку распределения systemSequence.removeRecIdSuspension(_tableId); return beginRecId; } Например, если подготовили к вставке 10 записей, а beginRecId = 12345, то соответственно будут значения RecId от 12345 до 12354 PS: Так и не понял, откуда все берут статический метод X++: systemSequence::flushCache();
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: Logger (1), Ace of Database (2), Pandasama (1). |
02.02.2017, 07:39 | #17 |
Участник
|
Да, я вчера пришел к подобной же мысли, только реализовать решил по-другому:
(чтобы не разбивать запрос на две части - подсчет количество и саму вставку) делаю заморозку выделения RecID выполняю запрос резервирую разницу между следующим RecId и фактическим RecId после вставки в таблицу снимаю заморозку но реализация что-то не работает: --start ----макс. recid в таблице 5642940489, systemsequences.nextval 5642940490 --suspend --before query ----макс. recid в таблице 5642940540, systemsequences.nextval 5642940740 ----systemsequence.reserve(1) = 5642940543 --execute insert query --after query ----макс. recid в таблице 5642945298, systemsequences.nextval 5642940740 ----systemsequence.reserve(1) = 5642940544 ----systemsequence.reserve(4754 {5642945245 - 5642940491 - разница между след. рекид и фактическим рекид}) = 5642940740 --removesuspend --а теперь проверим, какой RecId будет следующий --suspend ----systemsequence.reserve(1) = 5642940545 //будто бы не было reserve(4754) --removesuspend По идее, я зарезервировал 4754 RecId начиная с 5642940740 - то есть следующий номер должен быть 5642940740 + 4754 Или у меня неверные представления о работе резерва, и система не только резервирует, но ещё и по факту отслеживает вставку записей с этими RecId ? Впрочем, с выделением ДО запроса ситуация такая же: выделил скопом 10000 (больше реально вставляемых 4754), получил recid 5642990876, значение в systemSequence.nextVal = 5643000876 вставил запросом в таблицу выделил ещё 1 для проверки - получил 5642980716, значение меньше стартового RecId от первого выделения Последний раз редактировалось Pandasama; 02.02.2017 в 08:40. |
|
02.02.2017, 10:18 | #18 |
Участник
|
ну и вообще, вот такой джоб
X++: static void Job342(Args _args) { SystemSequence sysSeq = new SystemSequence(); int64 recId; ; sysSeq.suspendRecIds(tablenum(VendTable)); recId = sysSeq.reserveValues(1, tablenum(VendTable)); info(strfmt("after reserve 1 = %1", recId)); //5637264076 recId = sysSeq.reserveValues(10000, tablenum(VendTable)); info(strfmt("after reserve 10000 = %1", recId)); //5637264327 recId = sysSeq.reserveValues(1, tablenum(VendTable)); info(strfmt("after reserve 1 = %1", recId)); //5637264077 sysSeq.removeRecIdSuspension(tablenum(VendTable)); } 5637264076 5637264327 5637264077 то есть третий резерв возвращает значение меньше чем второй |
|
02.02.2017, 13:29 | #19 |
Участник
|
Цитата:
5637274077 Обратите вниманием на окончание: 74077, а не 64077, как у Вас. Возможно, Вы просто невнимательно посмотрели на число в этом разряде? Цитата:
Сообщение от Pandasama
(чтобы не разбивать запрос на две части - подсчет количество и саму вставку)
Разбивать по любому придется. Дело в том, что Axapta резервирует часть значение RecId. Т.е. определение значения по полю таблицы systemsequences.nextval ни о чем не говорит. Далеко не факт, что именно это значение и будет использовано в среде Axapta для генерации следующего значения. Как следствие, Вы рискуете присвоить не корректные значения RecId. Те, с которыми позже произойдет пересечение при обычной работе Axapta Другими словами недопустимо на основании systemsequences.nextval сфоромировать RecId, а потом попросить Axapta зарезервировать NN значений. Не получится, поскольку Axapta может начать резервирование вовсе не с того значения, которое указано в systemsequences.nextval Кроме того, с предварительным запросом во временную таблицу проще организовать нумерацию, при этом задержка по времени незначительная. У меня получается примерно так X++: // Этап 1 выборка во временную таблицу if object_id('tempDB..#NewData') is not null drop table #NewData; select (...) , identity(int,1,1) as RowNum into #NewData from (...) // Подсчет записей. Это значение считываем в Axapta select count(*) from #NewData // Этап 2 // Резервирование RecId в Axapta // И передача начального номера RecId в SQL // Этап 3 - Вставка в итоговую таблицу // beginRecId - переданное начальное значение insert into MyTable (... ,RecId ) select ... , #NewData.RowNum - 1 + beginRecId from #NewData
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... Последний раз редактировалось Владимир Максимов; 02.02.2017 в 13:41. |
|
Теги |
ax2009, recid, sql, systemsequences |
|
|