AXForum  
Go Back   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Forgotten Your Password?
Register Forum Rules FAQ Members List Today's Posts Search

 
 
Thread Tools Search this Thread Display Modes
Old 18.08.2016, 09:33   #1  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
Ax2009, сбросить кеш recid SystemSequences
Ситуация следующая:
Через SQL-запрос (запускаемый из X++) вставляю большое количество записей в таблицу.
Таблицу SystemSequences в том же запросе обновляю.
Однако при дальнейшей попытке вставить в эту же таблицу запись уже в X++ получаю конфликт recid.
При проверке обнаруживаю, что SystemSequence.ReserveValues() для этой таблицы возвращает значение меньшее, чем значение в таблице SystemSequences.

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

Вопрос: как в данной ситуации сбросить кэш выбранных RecId для того чтобы спокойно продолжить вставку в таблицу без конфликтов?
Old 18.08.2016, 09:57   #3  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
Все бы хорошо, но в моем Ax2009 в systemSequence в Ax2009 нет метода flushCache()
Old 18.08.2016, 10:05   #4  
Dron AKA andy is offline
Dron AKA andy
Moderator
 
944 / 253 (10) ++++++
Join Date: 27.03.2002
Location: Москва
В идеале - перезапустить бы АОС после обновления SystemSequences.
__________________
Андрей.
Old 18.08.2016, 10:13   #5  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
О да, было бы здорово, вот только у меня все это происходит внутри даже не одной пользовательской сессии, а одной непрерывной операции.
Old 18.08.2016, 10:18   #6  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
Путем эксперимента выяснилось, что, похоже, нужный эффект дает следующая комбинация:
1) обновляем значение в таблице SystemSequences
2) делаем suspendRecIds для нужной таблицы
3) делаем removeRecIdSuspension для неё
По крайней мере на моем конкретном примере это проблему решило, если это не случайное совпадение
Old 18.08.2016, 10:18   #7  
dech is offline
dech
Участник
dech's Avatar
Самостоятельные клиенты AX
 
650 / 352 (13) ++++++
Join Date: 25.06.2009
Location: Омск
Blog Entries: 3
А что именно вы делаете в запросе?
ИМХО, чистый SQL лучше использовать для экзотической SELECT-выборки. остальные операции следует выполнять штатными средствами. Если вы хотите вставить пачку записей, чем плох RecordInsertList?
__________________
// no comments
Old 18.08.2016, 10:25   #8  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c
Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы
Old 18.08.2016, 10:44   #9  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1243 (44) ++++++++
Join Date: 11.04.2008
Quote:
Originally Posted by Pandasama View Post
Для вставки на основе существующих записей необходим перебор записей через 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

Last edited by DSPIC; 18.08.2016 at 10:47.
This post has been rated by: dech (3).
Old 18.08.2016, 13:02   #10  
dech is offline
dech
Участник
dech's Avatar
Самостоятельные клиенты AX
 
650 / 352 (13) ++++++
Join Date: 25.06.2009
Location: Омск
Blog Entries: 3
Quote:
Originally Posted by Pandasama View Post
Для вставки на основе существующих записей необходим перебор записей через while select (или query), наполнение RecordInsertList и его вставка.
В SQL это делает одним каким-нибудь INSERT INTO xxx SELECT * FROM a JOIN b JOIN c
Что выполняется на порядок быстрее, вплоть до вставки в несколько миллионов записей за 5-10 минут (зависит от сложности джойнов). На X++ это занимает часы
Значит что-то мешает insert_recordset выполниться за одну инструкцию.
Вы уверены, что skipDataMethods(), skipDatabaseLog() не помогают?
__________________
// no comments
Old 18.08.2016, 13:21   #11  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
Нет возможности средствами X++ сделать insert_recordset - слишком сложные условия.
В SQL это выполняется (иногда через дополнительные промежуточные временные таблицы).
А в X++ это вырождается в цикл получения записей + вставка записей через InsertRecordList
В итоге SQL на порядки быстрее

Впрочем, речь не об о том, нужно ли писать в базу через SQL, а о том как сбросить кэш recid в 2009й версии.
Old 18.08.2016, 13:31   #12  
dech is offline
dech
Участник
dech's Avatar
Самостоятельные клиенты AX
 
650 / 352 (13) ++++++
Join Date: 25.06.2009
Location: Омск
Blog Entries: 3
Quote:
Originally Posted by Pandasama View Post
Нет возможности средствами X++ сделать insert_recordset - слишком сложные условия.
В SQL это выполняется (иногда через дополнительные промежуточные временные таблицы).
А в X++ это вырождается в цикл получения записей + вставка записей через InsertRecordList
В итоге SQL на порядки быстрее

Впрочем, речь не об о том, нужно ли писать в базу через SQL, а о том как сбросить кэш recid в 2009й версии.
А можно взглянуть на запрос? Уж очень заинтересовало.)))
По сабжу посмотрите здесь пример:
https://msdn.microsoft.com/en-us/library/aa638594.aspx
__________________
// no comments
Old 18.08.2016, 18:03   #13  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,724 / 1208 (44) ++++++++
Join Date: 13.01.2004
Blog Entries: 3
Да при чем здесь запрос! Основной тормоз Вы поимеете на закачке этой кучи записей на AOS и последующий возврат обратно на SQL. А время выполнения собственно запроса уже становится не критичным

Если речь идет о вставке миллионов записей, которые формируются непосредственно в базе SQL, то прокачка их через AOS для вставки средствами Axapta - крайне медленная операция.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Old 19.08.2016, 03:17   #14  
iCloud is offline
iCloud
Enjoy!
iCloud's Avatar
MCP
Злыдни
 
195 / 112 (4) +++++
Join Date: 06.03.2012
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();

Last edited by iCloud; 19.08.2016 at 03:20.
This post has been rated by: Владимир Максимов (2).
Old 01.02.2017, 13:56   #15  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
Quote:
Originally Posted by Pandasama View Post
Путем эксперимента выяснилось, что, похоже, нужный эффект дает следующая комбинация:
1) обновляем значение в таблице SystemSequences
2) делаем suspendRecIds для нужной таблицы
3) делаем removeRecIdSuspension для неё
По крайней мере на моем конкретном примере это проблему решило, если это не случайное совпадение
Как выяснилось - не помогло

Только диагноз теперь хуже:
при попытке выделить новые RecId для таблицы, для которой SystemSequence изменен в запросе - через N значений выделенных (руками выделенных или вставкой - не важно) - получаю мертвую блокировку на таблице SystemSequence. Ну и значения выделяются меньше, чем те что в SystemSequence прописаны - из каких-то старых кэшей, видимо
Old 01.02.2017, 17:33   #16  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,724 / 1208 (44) ++++++++
Join Date: 13.01.2004
Blog Entries: 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 Совсем нет
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
This post has been rated by: Logger (1), Ace of Database (2), Pandasama (1).
Old 02.02.2017, 07:39   #17  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
Да, я вчера пришел к подобной же мысли, только реализовать решил по-другому:
(чтобы не разбивать запрос на две части - подсчет количество и саму вставку)
делаю заморозку выделения 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 от первого выделения

Last edited by Pandasama; 02.02.2017 at 08:40.
Old 02.02.2017, 10:18   #18  
Pandasama is offline
Pandasama
Участник
 
473 / 140 (5) +++++
Join Date: 11.08.2014
Location: Барнаул
ну и вообще, вот такой джоб

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

то есть третий резерв возвращает значение меньше чем второй
Old 02.02.2017, 13:29   #19  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,724 / 1208 (44) ++++++++
Join Date: 13.01.2004
Blog Entries: 3
Quote:
Originally Posted by Pandasama View Post
выдает результаты:
5637264076
5637264327
5637264077

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

5637274077

Обратите вниманием на окончание: 74077, а не 64077, как у Вас. Возможно, Вы просто невнимательно посмотрели на число в этом разряде?


Quote:
Originally Posted by 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, то придется делать постоянные таблицы
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...

Last edited by Владимир Максимов; 02.02.2017 at 13:41.
Tags
ax2009, recid, sql, systemsequences

 

Similar Threads
Thread Thread Starter Forum Replies Last Post
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

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Рейтинг@Mail.ru
All times are GMT +3. The time now is 22:38.
Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Contacts E-mail, Advertising.