14.01.2021, 08:34 | #41 |
Участник
|
Цитата:
X++: while select SysDatabaseLog order by createdDateTime where SysDatabaseLog.RecId > lastRecId && (SysDatabaseLog.table == tableNum(custTable) || SysDatabaseLog.table == tableNum(DIRPARTYLOCATION) || SysDatabaseLog.table == tableNum(LOGISTICSELECTRONICADDRESS)) { }
__________________
Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/ |
|
14.01.2021, 11:02 | #42 |
Участник
|
RecId тоже непоследовательны. они выделяются пачками на клиента(по сто или около того) и потом расходуются по мере надобности
Последний раз редактировалось trud; 14.01.2021 в 11:39. |
|
14.01.2021, 11:48 | #43 |
Участник
|
Имеется в виду не RecId клиента, а RecId в таблице SysDatabaseLog
__________________
Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/ |
|
14.01.2021, 12:00 | #44 |
Участник
|
Прежде всего, согласен с Vadik, требование опрашивать 6M записей с частотой 1 раз в минуту - это какой-то перебор.
Но скорее всего, заказчик хотел иметь возможность опрашивать часто и опрашивать повторно некоторые разрезы (по группам, по условиям платежей, по наличию скидочной карточки и т.п.) поэтому простим такую формулировку. Критика предыдущих предложений 1. Change Tracking - хорош. Но слишком привязывает в MS SQL. В наше непростое время Great Again вендор-lock - это серьезный недостаток 2. ModifiedDateTime, RecID и прочие неубывающие последовательности - в топку, поскольку именно этот статус позволяет узнать что изменилось во всем справочнике, но не позволяет запросить измененные только в некоторых записях, и вынуждает делаеть полные запросы по всем 6M записей (а время еще и требует филигранной синхронизации времени на разных аосах/клиентах) 3. перехватывать событие/триггера изменений и записывать логи - чревато DDOS системы на расчетных полях типа себестоимости в складских проводках, алгоритм долбит обновлениями до посинения. (особенно категорически не надо использовать SysDatabaseLog) Что есть в стандартной Аксапте? 4. в аксапте уже есть поле recVersion. Ядро Аксапты использует это поле в рамках механизма оптимистической конкуренции в формах для того, чтобы узнать изменилась ли запись в других Аксаптах. Это то, что нам нужно! подход с recVersion придумал не майкрософт, но почитать об этом подходе можно здесь https://docs.microsoft.com/ru-ru/sql...n-transact-sql Кратко как поле RecVersion работает в аксапте: 1. RecVersion = 0 при создани записи 2. RecVersion = random(int) при любом обновлении записи (повторю: это делает ядро Аксапты, программировать это не надо) Инвариант: С огромной вероятностью recVersion после обновления будет отличаться от recVersion до обновления (ах это "почти"... длинные рассуждения о почти уникальных GUID и о инженерном подходе "на практике работоспособно") Что предлагается 5. 5.1. у вас есть справочник, состоящий из нескольких связанных таблиц (tab1, tab2 ... tabN) 5.2. у каждого справочника аксапта обслуживает служебное поле recVersion 5.3. Создайте shadow таблицу для вашего справочника tabShadow, в которой храните: 5.3.1. refRecVersion1, ... refRecVersionN - recVersion таблиц, которые вы выгрузили во внешнюю систему 5.3.2. [опционально] сериализованные значений полей, которые вы выгружаете. Важно, чтобы: 5.3.2.1. сериализованные значения можно было удобно сравнивать на равенство (изменились ли?) 5.3.2.2. сериализовать можно в аксаптовский container - тогда не надо будет программировать парсинг. Но конейнеры в MS SQL хранятся в (Memo)-полях. Со всеми вытекающими для производительности 5.3.3. FK к вашему справочнику, которые позволят однозначно связать shadow-запись и запись в справочнике (связь 0,1..0,1) 5.4. при каждой выгрузке обновляйте shadow-таблицу 5.5. shadow таблица позволит вам четко определить запросами 4 состояния: 5.5.1. есть запись в tab, нет записи в shadow - запись в справочнике создана, ни разу не выгружалась 5.5.2. есть запись в tab, есть запись в shadow, recVersion не совпадают - запись в справочнике изменилась, надо выгрузить 5.5.3. есть запись в tab, есть запись в shadow, recVersion совпадают - запись в справочнике не изменалась 5.5.4. ест записи в tab, есть запись в shadow - запись удалена, надо дать команду на удаление внешней системе 5.6. c shadow таблицей вы можете накладывать любые фильтры на справочник и получать измененные записи только среди отфильтрованных 5.7. shadow таблица не будет нагружать вашу систему паразитной нагрузкой в insert/update/delete и логах. будет работать только по запросу там еще куча соображений. но пока хватит. Последний раз редактировалось mazzy; 14.01.2021 в 12:07. |
|
|
За это сообщение автора поблагодарили: sukhanchik (10), vmoskalenko (4). |
14.01.2021, 12:14 | #45 |
Боец
|
Буквально недавно была такая же задача. Как сделали:
1. Представляем себе, что CustTable+Addresses+Contacts и прочее прилепленное - это XML документ для выгрузки, где CustTable - верхняя запись 2. Каждый раз, когда изменяестя CustTable (либо любая из дочерних) мы формируем этот XML и выгружаем куда-то там во вне. Но при этом, мы храним последнюю выгруженную версию XML где-то в отдельной таблице. 3. Естетсвенно, каждый раз, когда мы хотим выгрузить XML, мы сравниваем его с последней выгруженной версией. Выгружаем только, если отличаются. 4. Важно, что непосредственно выгрузка делается в Batch на основании таблицы-очереди. Т.е. п.2,3 формируют очередь на выгрузку, когда whereas отдельный Batch расталкивает её. Это развяжет по транзакциям, обезопасив работу пользователей и SQL. 4.1 В таблице-очереди мы храним не сам XML, а ссылку на запись верхнюю запись, что изменилась,т.к. ввиду периодичности работы Batch, хранимый XML может потенциально устареть. Из некрасивого: ============= - триггеры придется повесить на все таблицы, изменения которых влечёт формирование нового XML - придется хранить последнюю версию XML (или его хэш) - нужно покодить Из красивого: =========== - Гантированно выгружаете только в том случае, когда изменились нужные для выгрузки поля - Никаких завязок на modifiedDate\SystemLog, что ведёт приямиков в АД - Будет работать в любой версии AX. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
14.01.2021, 12:17 | #46 |
Участник
|
Я так понимаю, что основная проблема у автора в том, что:
Может быть все-таки есть возможность как-то систематизировать то, кто что получает или это, действительно, непредсказуемо? Кстати, да, у mazzy прозвучала неплохая мысль про удаление. А как его реплицировать? Последний раз редактировалось Raven Melancholic; 14.01.2021 в 12:19. |
|
14.01.2021, 12:55 | #47 |
Участник
|
раз уж все равно кодите сериализацию, то лучше хранить для сравнения какой-нибудь хэш с ограниченной длиной от xml.
тогда для хэша можно использовать обычный NVarChar, а не Memo xml можно хранить только для вывода сообщений человеку что именно изменилось. |
|
14.01.2021, 13:00 | #48 |
Боец
|
Цитата:
Сообщение от mazzy
Прежде всего, согласен с Vadik, требование опрашивать 6M записей с частотой 1 раз в минуту - это какой-то перебор.
Но скорее всего, заказчик хотел иметь возможность опрашивать часто и опрашивать повторно некоторые разрезы (по группам, по условиям платежей, по наличию скидочной карточки и т.п.) поэтому простим такую формулировку. Критика предыдущих предложений 1. Change Tracking - хорош. Но слишком привязывает в MS SQL. В наше непростое время Great Again вендор-lock - это серьезный недостаток 2. ModifiedDateTime, RecID и прочие неубывающие последовательности - в топку, поскольку именно этот статус позволяет узнать что изменилось во всем справочнике, но не позволяет запросить измененные только в некоторых записях, и вынуждает делаеть полные запросы по всем 6M записей (а время еще и требует филигранной синхронизации времени на разных аосах/клиентах) 3. перехватывать событие/триггера изменений и записывать логи - чревато DDOS системы на расчетных полях типа себестоимости в складских проводках, алгоритм долбит обновлениями до посинения. (особенно категорически не надо использовать SysDatabaseLog) Что есть в стандартной Аксапте? 4. в аксапте уже есть поле recVersion. Ядро Аксапты использует это поле в рамках механизма оптимистической конкуренции в формах для того, чтобы узнать изменилась ли запись в других Аксаптах. Это то, что нам нужно! подход с recVersion придумал не майкрософт, но почитать об этом подходе можно здесь https://docs.microsoft.com/ru-ru/sql...n-transact-sql Кратко как поле RecVersion работает в аксапте: 1. RecVersion = 0 при создани записи 2. RecVersion = random(int) при любом обновлении записи (повторю: это делает ядро Аксапты, программировать это не надо) Инвариант: С огромной вероятностью recVersion после обновления будет отличаться от recVersion до обновления (ах это "почти"... длинные рассуждения о почти уникальных GUID и о инженерном подходе "на практике работоспособно") Что предлагается 5. 5.1. у вас есть справочник, состоящий из нескольких связанных таблиц (tab1, tab2 ... tabN) 5.2. у каждого справочника аксапта обслуживает служебное поле recVersion 5.3. Создайте shadow таблицу для вашего справочника tabShadow, в которой храните: 5.3.1. refRecVersion1, ... refRecVersionN - recVersion таблиц, которые вы выгрузили во внешнюю систему 5.3.2. [опционально] сериализованные значений полей, которые вы выгружаете. Важно, чтобы: 5.3.2.1. сериализованные значения можно было удобно сравнивать на равенство (изменились ли?) 5.3.2.2. сериализовать можно в аксаптовский container - тогда не надо будет программировать парсинг. Но конейнеры в MS SQL хранятся в (Memo)-полях. Со всеми вытекающими для производительности 5.3.3. FK к вашему справочнику, которые позволят однозначно связать shadow-запись и запись в справочнике (связь 0,1..0,1) 5.4. при каждой выгрузке обновляйте shadow-таблицу 5.5. shadow таблица позволит вам четко определить запросами 4 состояния: 5.5.1. есть запись в tab, нет записи в shadow - запись в справочнике создана, ни разу не выгружалась 5.5.2. есть запись в tab, есть запись в shadow, recVersion не совпадают - запись в справочнике изменилась, надо выгрузить 5.5.3. есть запись в tab, есть запись в shadow, recVersion совпадают - запись в справочнике не изменалась 5.5.4. ест записи в tab, есть запись в shadow - запись удалена, надо дать команду на удаление внешней системе 5.6. c shadow таблицей вы можете накладывать любые фильтры на справочник и получать измененные записи только среди отфильтрованных 5.7. shadow таблица не будет нагружать вашу систему паразитной нагрузкой в insert/update/delete и логах. будет работать только по запросу там еще куча соображений. но пока хватит. |
|
14.01.2021, 13:07 | #49 |
Участник
|
Цитата:
поэтому я уже написал: Цитата:
5.3.2. [опционально] сериализованные значений полей, которые вы выгружаете.
но тут снова возникает "выбор инженера": упростить хранилище за счет того, что будут передаваться некоторое количество избыточных команд, или не передавать ничего избыточного собственно эту часть я и вырезал из своих рассуждений: допустить повторную передачу данных или кодить точные алгоритмы... Цитата:
но это если кодить. Последний раз редактировалось mazzy; 14.01.2021 в 13:11. |
|
14.01.2021, 13:07 | #50 |
Участник
|
SysDatabaseLog - и есть тот самый shadow. И понятно, что нельзя логировать таблицы типа проводок. Речь же идет о справочнике. А тут сам бог велел логировать, чтобы потом разбираться: кто ввел неправильные данные.
И RecId имеется в виду для таблицы SysDatabaseLog. И никаких 6 миллионов записей не надо считывать каждый раз. В примере я показал, что 26 тысяч запросов к SysDatabaseLog очень быстро работают для выборки нужных данных из 74 миллионов записей в SysDatabaseLog. А у автора вообще достаточно написать 1 запрос к таблице к SysDatabaseLog Я специально показал такой неоптимизированный пример с 26 тысячами запросов, чтобы было видно, что таблица SysDatabaseLog быстрая.
__________________
Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/ |
|
14.01.2021, 13:16 | #51 |
Боец
|
Цитата:
Сообщение от mazzy
Угу. добавить еще проверку на recVersion, чтобы не сравнивать длинные строки
|
|
14.01.2021, 13:17 | #52 |
Участник
|
Но вообще-то я согласен, что именно для этих целей использовать SysDatabaseLog неудобно по той причине, что там неудобно ловить момент изменения именно нужного поля. Хотя вроде мой джоб работает, но как-то сравнивать между собой два контейнера некрасиво смотрится. Неклассически что-ли.
Но все-таки это работает, и довольно быстро.
__________________
Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/ |
|
14.01.2021, 13:17 | #53 |
Участник
|
нет. в SysDatabaseLog добавляются записи при каждом чихе.
в shadow таблица добавляется максимум 1 запись для каждой записи справочника. Цитата:
но видели мы на практике эти справочники... и что туда пихают. особенно, если в справочнике появляется "выгрузка в другую систему" Цитата:
чтобы выгружать - нет. никто ж не запрещает и shadow сделать, и в SysDatabaseLog включить. речь идет о том, что не надо использовать SysDatabaseLog для задач где нужно только "последнее" состояние. Цитата:
Сообщение от Ace of Database
И RecId имеется в виду для таблицы SysDatabaseLog. И никаких 6 миллионов записей не надо считывать каждый раз. В примере я показал, что 26 тысяч запросов к SysDatabaseLog очень быстро работают для выборки нужных данных из 74 миллионов записей в SysDatabaseLog.
А у автора вообще достаточно написать 1 запрос к таблице к SysDatabaseLog Я специально показал такой неоптимизированный пример с 26 тысячами запросов, чтобы было видно, что таблица SysDatabaseLog быстрая. |
|
14.01.2021, 13:19 | #54 |
Участник
|
Цитата:
именно, наизнанку. Цитата:
Сообщение от DSPIC
Можно, было бы, но много дочерних таблиц... А от них нужно прийти к верхенму CustTable. Т.е. ты получишь 500К изменившихся Addresses, из которых придется найти только 50 клиентов, подлежащих выгрузке. Ну такое: неоптимально и наизнанку. Тригерры всё-таки нужно вешать, а с ними и recVersion сравнивать бессмысленно, т.к. заведомо поменяется.
я тоже через такие рассуждения прошел |
|
14.01.2021, 13:19 | #55 |
Участник
|
Цитата:
Сообщение от DSPIC
Имеешь ввиду - убрать триггеры на update\insert и сканить таблицы на предмет изменившегося recVersion, а потом уже смотреть, изменились ли выгружаемые поля? Можно, было бы, но много дочерних таблиц... А от них нужно прийти к верхенму CustTable. Т.е. ты получишь 500К изменившихся Addresses, из которых придется найти только 50 клиентов, подлежащих выгрузке. Ну такое: неоптимально и наизнанку. Тригерры всё-таки нужно вешать, а с ними и recVersion сравнивать бессмысленно, т.к. заведомо поменяется.
__________________
Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/ |
|
14.01.2021, 13:29 | #56 |
Участник
|
Цитата:
но раз уж дошло до дочерних таблиц. на дочерних таблицах так или иначе, но будут заданы constraints на FK (в аксапте такие валидации выполняются в validateWrite, задаются в reltation) т.е. чтобы внешняя система смогла принять данные, данные должны быть переданы в определенном порядке - сначала родитель, потом потомок. т.е. в коде не будет простой выборки всех измененных данных. придется делать более сложный алгоритм. особенно если есть отношения (id, parentId) в самой таблице. тогда надо будет не только таблицы сортировать, но и измененные записи внутри таблиц |
|
14.01.2021, 13:33 | #57 |
Боец
|
Цитата:
Пример: Выгрузке подлежат клиенты, у которых CommissionSalesGroup.Export=Yes. Выгружать нужно в т.ч., если изменились их адреса. Итак, поменялся RecVersion у 10К адресов, в которые входят наши 5 клиентов для выгрузки.Ну, вдовесок там ещё контакты и прочая DirParty лабуда. Аж интересно мне.. |
|
14.01.2021, 13:41 | #58 |
Боец
|
О, отличная мысль. Я так буду заказчикам писать, когда с эстимейтами мимо выйдет.
Цитата:
Сообщение от mazzy
на дочерних таблицах так или иначе, но будут заданы constraints на FK (в аксапте такие валидации выполняются в validateWrite, задаются в reltation)
т.е. чтобы внешняя система смогла принять данные, данные должны быть переданы в определенном порядке - сначала родитель, потом потомок. т.е. в коде не будет простой выборки всех измененных данных. придется делать более сложный алгоритм. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
14.01.2021, 13:43 | #59 |
Участник
|
Цитата:
Сообщение от DSPIC
Начинается... Подумал, не знаю. Поделись, сэкономь мне 50$ времени
Пример: Выгрузке подлежат клиенты, у которых CommissionSalesGroup.Export=Yes. Выгружать нужно в т.ч., если изменились их адреса. Итак, поменялся RecVersion у 10К адресов, в которые входят наши 5 клиентов для выгрузки.Ну, вдовесок там ещё контакты и прочая DirParty лабуда. Аж интересно мне.. выгрузи только те, что относятся к измененным клиентам. ты говоришь: * клиенты используют адреса в FK * это бизнес локика наверняка заложена и в Аксапте и во внешней системе * значит с огромной вероятностью во внешней системе будут заданы constraints на адреса у клиента * это значит, чтобы приемник смог принять без ошибок, система источник ДОЛЖНА сначала передать адреса, а уж потом клиентов. * будет ли источник передавать сначала все 10К изменившихся адресов или будет как то приоретизировать... вопрос реализации, а не вопрос подхода. и я сильно подозреваю, что этот вопрос уходит сильно за рамки исходного вопроса. говорю жеж, подумай еще раз. там много соображений, относящихся к бизнес-логике и к инфраструктуре, а не к кодингу. кодинг - не так уж и сложен в этой задаче. а прикинь есть еще удаление. и на приемнике может присутстовать каскадное удаление данных Последний раз редактировалось mazzy; 14.01.2021 в 13:49. |
|
14.01.2021, 13:44 | #60 |
Участник
|
И в самом деле!
Никакого порядка! |
|
Теги |
aif, ax2012, change tracking, интеграция, как правильно |
|
|