AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 18.08.2016, 09:33   #1  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Ax2009, сбросить кеш recid SystemSequences
Ситуация следующая:
Через SQL-запрос (запускаемый из X++) вставляю большое количество записей в таблицу.
Таблицу SystemSequences в том же запросе обновляю.
Однако при дальнейшей попытке вставить в эту же таблицу запись уже в X++ получаю конфликт recid.
При проверке обнаруживаю, что SystemSequence.ReserveValues() для этой таблицы возвращает значение меньшее, чем значение в таблице SystemSequences.

Насколько я знаю, в каждой сессии RecId для таблицы выделяются пачками, которая кешируется в клиенте. И подозреваю, что следующий RecId после моих манипуляций с данными, выбирается все ещё из старого кеша, а не берется новая пачка значений из таблицы SystemSequences.

Вопрос: как в данной ситуации сбросить кэш выбранных RecId для того чтобы спокойно продолжить вставку в таблицу без конфликтов?
Старый 18.08.2016, 09:57   #3  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Все бы хорошо, но в моем Ax2009 в systemSequence в Ax2009 нет метода flushCache()
Старый 18.08.2016, 10:05   #4  
Dron AKA andy is offline
Dron AKA andy
Moderator
 
944 / 253 (10) ++++++
Регистрация: 27.03.2002
Адрес: Москва
В идеале - перезапустить бы АОС после обновления SystemSequences.
__________________
Андрей.
Старый 18.08.2016, 10:13   #5  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
О да, было бы здорово, вот только у меня все это происходит внутри даже не одной пользовательской сессии, а одной непрерывной операции.
Старый 18.08.2016, 10:18   #6  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Путем эксперимента выяснилось, что, похоже, нужный эффект дает следующая комбинация:
1) обновляем значение в таблице SystemSequences
2) делаем suspendRecIds для нужной таблицы
3) делаем removeRecIdSuspension для неё
По крайней мере на моем конкретном примере это проблему решило, если это не случайное совпадение
Старый 18.08.2016, 10:18   #7  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
647 / 350 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
А что именно вы делаете в запросе?
ИМХО, чистый SQL лучше использовать для экзотической SELECT-выборки. остальные операции следует выполнять штатными средствами. Если вы хотите вставить пачку записей, чем плох RecordInsertList?
__________________
// no comments
Старый 18.08.2016, 10:25   #8  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c
Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы
Старый 18.08.2016, 10:44   #9  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1235 (44) ++++++++
Регистрация: 11.04.2008
Цитата:
Сообщение от Pandasama Посмотреть сообщение
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c
Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы
- если 2012 и выше, то в идеале лучше так сделать так insert_recordset [AX 2012]. И не забыть про fall back to record-by-record operations. См. также Query::insert_recordset Method [AX 2012]

- если версия по-старше, то пара suspendRecIds + removeRecIdSuspension обязательна.

- Обновлять же самому SystemSequence допускается только в случаях Application Maintance

Последний раз редактировалось DSPIC; 18.08.2016 в 10:47.
За это сообщение автора поблагодарили: dech (3).
Старый 18.08.2016, 13:02   #10  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
647 / 350 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от Pandasama Посмотреть сообщение
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c
Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы
Значит что-то мешает insert_recordset выполниться за одну инструкцию.
Вы уверены, что skipDataMethods(), skipDatabaseLog() не помогают?
__________________
// no comments
Старый 18.08.2016, 13:21   #11  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Нет возможности средствами X++ сделать insert_recordset - слишком сложные условия.
В SQL это выполняется (иногда через дополнительные промежуточные временные таблицы).
А в X++ это вырождается в цикл получения записей + вставка записей через InsertRecordList
В итоге SQL на порядки быстрее

Впрочем, речь не об о том, нужно ли писать в базу через SQL, а о том как сбросить кэш recid в 2009й версии.
Старый 18.08.2016, 13:31   #12  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
647 / 350 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от 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   #13  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,685 / 1189 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Да при чем здесь запрос! Основной тормоз Вы поимеете на закачке этой кучи записей на AOS и последующий возврат обратно на SQL. А время выполнения собственно запроса уже становится не критичным

Если речь идет о вставке миллионов записей, которые формируются непосредственно в базе SQL, то прокачка их через AOS для вставки средствами Axapta - крайне медленная операция.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 19.08.2016, 03:17   #14  
iCloud is offline
iCloud
Enjoy!
Аватар для iCloud
MCP
Злыдни
 
195 / 108 (4) +++++
Регистрация: 06.03.2012
Адрес: Moscow/Ukraine/Malta
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(); 
      }
AX 4.0:
X++:
    systemSequence::flushCache();

Последний раз редактировалось iCloud; 19.08.2016 в 03:20.
За это сообщение автора поблагодарили: Владимир Максимов (2).
Старый 01.02.2017, 13:56   #15  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Цитата:
Сообщение от Pandasama Посмотреть сообщение
Путем эксперимента выяснилось, что, похоже, нужный эффект дает следующая комбинация:
1) обновляем значение в таблице SystemSequences
2) делаем suspendRecIds для нужной таблицы
3) делаем removeRecIdSuspension для неё
По крайней мере на моем конкретном примере это проблему решило, если это не случайное совпадение
Как выяснилось - не помогло

Только диагноз теперь хуже:
при попытке выделить новые RecId для таблицы, для которой SystemSequence изменен в запросе - через N значений выделенных (руками выделенных или вставкой - не важно) - получаю мертвую блокировку на таблице SystemSequence. Ну и значения выделяются меньше, чем те что в SystemSequence прописаны - из каких-то старых кэшей, видимо
Старый 01.02.2017, 17:33   #16  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,685 / 1189 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Не обновляйте вручную таблицу 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;
}
Далее в SQL передаем как параметр полученное значение beginRecId и прибавляем к нему порядковый номер вставляемой записи (начиная нумерацию с нуля).

Например, если подготовили к вставке 10 записей, а beginRecId = 12345, то соответственно будут значения RecId от 12345 до 12354

PS: Так и не понял, откуда все берут статический метод

X++:
systemSequence::flushCache();
Нет такого в Ax4.0 Совсем нет
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
За это сообщение автора поблагодарили: Logger (1), Ace of Database (2), Pandasama (1).
Старый 02.02.2017, 07:39   #17  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
Да, я вчера пришел к подобной же мысли, только реализовать решил по-другому:
(чтобы не разбивать запрос на две части - подсчет количество и саму вставку)
делаю заморозку выделения 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  
Pandasama is offline
Pandasama
Участник
 
456 / 134 (5) +++++
Регистрация: 11.08.2014
Адрес: Барнаул
ну и вообще, вот такой джоб

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  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,685 / 1189 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от Pandasama Посмотреть сообщение
выдает результаты:
5637264076
5637264327
5637264077

то есть третий резерв возвращает значение меньше чем второй
У меня возвращает корректно. Применительно к Вашему примеру последнее число было бы

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
Я использую динамическое формирование запроса в среде Axapta, поэтому временные таблицы. Если использовать хранимые процедуры SQL, то придется делать постоянные таблицы
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...

Последний раз редактировалось Владимир Максимов; 02.02.2017 в 13:41.
Теги
ax2009, recid, sql, systemsequences

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
SystemSequences - Выделение RecId kashperuk DAX: Программирование 11 27.08.2013 15:02
ax2009. зачем нужно создавать индекс по recID, если включены CreatedDateTime или ModifiedDateTime? mazzy DAX: Программирование 1 17.07.2011 23:01
Формирование RecId при вставке в таблицу AX из SQL Server Hyper DAX: Программирование 20 28.06.2011 17:30
axforum blogs: Переделываем RecId в таблицах Blog bot DAX Blogs 0 06.05.2011 19:11
aEremenko: Дефрагментация RecID Blog bot DAX Blogs 2 06.03.2007 22:25

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 02:17.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.