| 
			
			 | 
		#21 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			А если просто в журнале базы данных SysDatabaseLog искать все записи за последнюю минуту, у которых нужный TableId ?
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#22 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Я как-то делал отчет, который из журнала базы данных достает историю изменения выбранных полей. Вроде довольно быстро работает на базе в 500 Гб. Правда там журнал базы данных хранился только за последние 2 недели, а потом обрезался. 
		
		
		
		
		
		
			А вам всего-то надо узнать какие записи изменились из списка нужных вам таблиц. 
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#23 | 
| 
			
			 Модератор 
		
			
	 | 
	
	
	
		
		
		
		 
			
			"Довольно быстро", или "достаточно быстро чтобы непрерывно делать это 10+ раз в минуту", учитывая других читателей-писателей в лог ?
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
		
			-ТСЯ или -ТЬСЯ ? Последний раз редактировалось Vadik; 13.01.2021 в 14:53.  | 
| 
	
 | 
| 
			
			 | 
		#24 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
Цитата: 
	
  Но идея хорошая если лог небольшой и скорость будет приемлемая.Опять таки надо пробовать.На худой конец можно создать свой лог-таблицу под эту задачу. У нас практикуется репликация о которой говорил axm2017. Цитата: 
	
Если под эту задачу сделать свою таблицу, да с толковыми индексами, то будет очень быстро работать. 
				__________________ 
		
		
		
		
		
			-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. Последний раз редактировалось Pustik; 13.01.2021 в 15:00.  | 
| 
	
 | 
| 
			
			 | 
		#25 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
 | 
| 
	
 | 
| 
			
			 | 
		#26 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
А запрос к таблице SysDatabaseLog вроде быстро выполнялся. Прошло уже несколько лет с того времени. По-любому надо пробовать. По-моему это самый простой способ решить данную проблему. А начинать пробовать надо с простых способов. Хотя все-таки поймать изменение конкретного поля через таблицу SysDatabaseLog - задача не очень тривиальная, но пример как это сделать есть. Даже на этом форуме выкладывали. 
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#27 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Задайте период x -1 час или -1 день раз такие длинные по времени транзакции из общих соображений количество изменений для данных таблиц все одно невелико.  
		
		
		
		
		
		
		
		
			Можно и в лог измененных записей поиграть конечно. . Последний раз редактировалось axm2017; 13.01.2021 в 15:40.  | 
| 
	
 | 
| 
			
			 | 
		#28 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Запустил у себя сейчас такой джоб. 
		
		
		
		
		
		
			Для 26 тысяч клиентов он отработал примерно за 2 минуты (если убрать вывод в инфолог) Это для Аксапты версии 3.0 X++: static void sysDatabaseLogFieldChangedCustAxForum(Args _args) { CustTable custTable; SysDatabaseLog SysDatabaseLog; int i; container tmp; SysOperationProgress sysOperationProgress = new SysOperationProgress(1); int stepCount; int total; UserInfo UserInfo; ; select count(RecId) from custTable; total = custTable.RecId; sysOperationProgress.setTotal(total); while select custTable { stepCount ++; sysOperationProgress.setCount(stepCount); sysOperationProgress.setText(strFmt("%1 запись из %2", stepCount, total)); while select SysDatabaseLog order by createdDate, createdTime where SysDatabaseLog.LogRecId == custTable.RecId && SysDatabaseLog.table == custTable.TableId { if (typeOf(conpeek(SysDatabaseLog.Data, 1)) == Types::Container) { for ( i = 1; i <= conlen(SysDatabaseLog.data); i ++) { tmp = conpeek(SysDatabaseLog.Data, i ); if (fieldExt2Id(conpeek(tmp, 1)) == fieldnum(custTable, zResponsibleDivision)) { if(conpeek(tmp, 3) != conpeek(tmp, 2)) { select firstonly UserInfo where UserInfo.Id == SysDatabaseLog.createdBy; info(strfmt("%1 ~ %2 ~ %3 ~ %4 ~ %5", custTable.AccountNum, UserInfo.name, SysDatabaseLog.createdDate, conpeek(tmp, 3),conpeek(tmp, 2) )); } } } } } } } 
				__________________ 
		
		
		
		
		
			Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/ Последний раз редактировалось Ace of Database; 13.01.2021 в 15:41.  | 
| 
	
 | 
| 
			
			 | 
		#29 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Т.е. 26000 вызовов select для таблицы SysDatabaseLog  срабатывают за 2 минуты и плюс еще время на парсинг
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#30 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			В таблице SysDatabaseLog сейчас 74 миллиона записей. Похоже, что ее перестали обрезать
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#31 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Автор топика может для своих нужд переписать джоб так, чтобы он отправил всего один запрос к SysDatabaseLog вместо 26 тысяч запросов, но тогда придется усложнить парсинг, чтобы сохранять предыдущие значения полей для каждой записи. Все-таки у него 6 миллионов клиентов, а не 26 тысяч. Но в выборку у него попадут не более нескольких сотен записей, т.к. ему нужны изменения только за последнюю минуту.
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#32 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Там главная проблема в том что связи сложны. Ну т.е. я там выше привел пример запроса который они сейчас используют. (Выгрузка измененных клиентов во внешнюю систему) 
		
		
		
		
		
		
		
	Т.е. понятно что для одной таблицы это все сделать просто. С outer join у вас будет 8 вариантов в различных комбинациях. Если делать с интервалом несколько часов(чтобы покрыть длинные транзакции) то данных будет много  | 
| 
	
 | 
| 
			
			 | 
		#33 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			А если вот так сделать? 
		
		
		
		
		
		
			А потом уже сопоставлять отобранные записи вручную между собой через всякие Map'ы ? X++: while select SysDatabaseLog order by createdDate, createdTime where SysDatabaseLog.table == tableNum(custTable) || SysDatabaseLog.table == tableNum(DIRPARTYLOCATION) || SysDatabaseLog.table == tableNum(LOGISTICSELECTRONICADDRESS) { } 
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#34 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Вот так запихнуть всю историю в мапы, а потом мапы сопоставляеть между собой 
		
		
		
		
		
		
			X++: Map mapCustTable = new Map(Types::String, Types::Container), Map mapDIRPARTYLOCATION = new Map(Types::String, Types::Container), Map mapLOGISTICSELECTRONICADDRESS = new Map(Types::String, Types::Container), while select SysDatabaseLog order by createdDate, createdTime where SysDatabaseLog.table == tableNum(custTable) || SysDatabaseLog.table == tableNum(DIRPARTYLOCATION) || SysDatabaseLog.table == tableNum(LOGISTICSELECTRONICADDRESS) { switch(SysDatabaseLog.table) { case tableNum(custTable): mapCustTable.insert(strfmt("%1_%2_%3", SysDatabaseLog.LogRecId, SysDatabaseLog.CreatedDate, SysDatabaseLog.CreatedTime), SysDatabaseLog.data); break; } } 
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#35 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Т.е. у вас будет  8 мапов. 
		
		
		
		
		
		
			Например, если в мапе mapLOGISTICSELECTRONICADDRESS изменилось нужное вам поле, то вы уже можете обычным для Аксапты способом через таблицу LOGISTICSELECTRONICADDRESS выйти на того клиента, и узнать его код. И даже сопоставлять между собой эти 8 мапов не надо. 
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#36 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Вот как-то так: 
		
		
		
		
		
		
			X++:     LogisticsElectronicAddress logisticsElectronicAddress;
    MapEnumerator me = new MapEnumerator(mapLogisticsElectronicAddress);
    CustTable custTable;
    RefRecId refRecId;
    while (me && me.moveNext())
    {
        refRecId = str2Int64(conPeek(str2Con_RU(me.currentKey(), "_"), 1));
        logisticsElectronicAddress = LogisticsElectronicAddress::findRecId(refRecId);
        custTable = CustTable::findByPartyRecId(logisticsElectronicAddress .PrivateForParty);
    }
				__________________ 
		
		
		
		
		
			Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/ Последний раз редактировалось Ace of Database; 13.01.2021 в 17:13.  | 
| 
	
 | 
| 
			
			 | 
		#37 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			что-то я потерял идею 
		
		
		
		
		
		
		
	X++: while select SysDatabaseLog order by createdDate, createdTime where SysDatabaseLog.table == tableNum(custTable) || SysDatabaseLog.table == tableNum(DIRPARTYLOCATION) || SysDatabaseLog.table == tableNum(LOGISTICSELECTRONICADDRESS)  | 
| 
	
 | 
| 
			
			 | 
		#38 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Это пример был из АХ3. Там дата и время создания записи хранятся в отдельных полях 
		
		
		
		
		
		
			А для АХ 2012, чтобы вернуть все изменения за последнюю минуту, можно написать так: X++: while select SysDatabaseLog order by createdDateTime where SysDatabaseLog.createdDateTime >= DateTimeUtil::addMinutes(DateTimeUtil::utcNow(), -1) && (SysDatabaseLog.table == tableNum(custTable) || SysDatabaseLog.table == tableNum(DIRPARTYLOCATION) || SysDatabaseLog.table == tableNum(LOGISTICSELECTRONICADDRESS)) { } 
				__________________ 
		
		
		
		
	Мои утилиты для Аксапты версий 3.0-2012: http://aceofdatabase.blogspot.com/  | 
| 
	
 | 
| 
			
			 | 
		#39 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Ну это будут изменения за последнюю минуту по которым завершилась транзакция в момент запуска данного запроса. Также могут быть изменения за конкретно эту же минуту по которым транзакция еще не завершилась, они появятся позже, как она завершится. Как предлагаете их искать?
		 
		
		
		
		
		
		
		
	 | 
| 
	
 | 
| 
			
			 | 
		#40 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
1) запоминаем время запуска текущей репликации startDateTime = DateTimeUtil::utcNow() 2) достаем из таблички дату-время запуска последней репликации = lastDateTime 3) пошла репликация: X++: while select SysDatabaseLog order by createdDateTime where SysDatabaseLog.createdDateTime >= lastDateTime && (SysDatabaseLog.table == tableNum(custTable) || SysDatabaseLog.table == tableNum(DIRPARTYLOCATION) || SysDatabaseLog.table == tableNum(LOGISTICSELECTRONICADDRESS)) { } PS: А меняя в этой табличке дату-время запуска последней репликации можно управлять интервалом минута, месяц, год и т.д. 
				__________________ 
		
		
		
		
		
			-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. Последний раз редактировалось Pustik; 14.01.2021 в 08:26.  | 
| 
	
 | 
| Теги | 
| aif, ax2012, change tracking, интеграция, как правильно | 
| 
	
	 | 
	
		
		
  |