| 
			
			 | 
		#1 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
			
			
			Axapta - SQL transfer
			 
			
			Добрый день 
		
		
		
		
		
		
			Появилась задачка оптимизировать одну джобы в аксапте, котороая по времени занимает до 80-ти часов, в основном из-за количества записей. Структура кода следующая: while selec a join b join c //возвращает под сотню тысяч записей. { while (bla bla ) // несколько повторов на одну запись { someoperation(); recordinsertlist.ins(); } recordinsertlist.insertdatabse(); } Моя идея - переписать это счастье на сиквеле ради скорости. Есть ли у кого опыт или соображения по поводу того насколько это сложно и насколько выгодно в плане времени исполнения? Заранее спасибо 
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#2 | 
| 
			
			 Member 
		
			
	 | 
	
	
	
		
		
		
		 
			
			В Аксапте? 
		
		
		
		
		
		
			А как RecId вы будете выделять? И задачка у вас... нетипичная. Что вы делаете (зачем вставлять в базу столько записей)? 
				__________________ 
		
		
		
		
	С уважением, glibs®  | 
| 
	
 | 
| 
			
			 | 
		#3 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
Задача - прогноз потребления, выручки от продажы электроенергии при разных ценах вплоть до каждого клиента (а у энергетических компаний их сотни тысяч - миллионы). Вот так и набегает. Последний раз было 1.1М записей... 
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#4 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Вы точно уверены в отсутствии возможности оптимизации вашего 
		
		
		
		
		
		
		
	while selecе a join b join c //возвращает под сотню тысяч записей. { while (bla bla ) // несколько повторов на одну запись { someoperation(); recordinsertlist.ins(); } recordinsertlist.insertdatabse(); } ??? Как показывает опыт, проигрыш X++ по сравнению с чистым T-SQL конечно же бесспорный, но не настолько катастрофичный, что бы пренебречь высокоуровневой средой ![]() Job - задача одного-двух использований? Тогда наверняка есть верхняя грань приемлемости времени выполнения Job'а. Не нужен 100% оптимальный результат, достаточно достичь указанной величины. Оптимизируя 20% кода можно достичь 80% возможной оптимальности, imho  
		 | 
| 
	
 | 
| 
			
			 | 
		#5 | 
| 
			
			 Member 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Значит смотрите. Есть два подхода решения проблемы: 
		
		
		
		
		
		
			1. Лбом сквозь стену. 2. Рациональный. Первый психологически проще. Можно и прямой запрос написать, и в Аксапте что-то делать. Второй предполагает выработку оптимального решения. Вы говорите, что у вас за 1 000 000 проводок. Кто-то их поштучно просматривает? Они действительно нужны? М.б. можно свернутые сделать? И как вы их анализируете? М.б. их в OLAP можно перенести? Ну и т.д. Если решать в лоб, то сравните скорость отработки вашего джоба, но с полностью закомментированной вставкой. Причем в одном случае это делайте в транзакции, а во втором не в транзакции. Из разницы во времени вы поймете грубоватую оценку того, сколько времени уходит на чтение, сколько на вставку, и сколько на блокировки. Предположительно, у вас тормозит вставка. Потом посмотрите, в какую таблицу вы пишете. Там есть индексы (особенно кластерные)? 
				__________________ 
		
		
		
		
	С уважением, glibs®  | 
| 
	
 | 
| 
			
			 | 
		#6 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
		
			Сообщение от fomenka
			 
 
			Вы точно уверены в отсутствии возможности оптимизации вашего 
		
	while selecе a join b join c //возвращает под сотню тысяч записей. { while (bla bla ) // несколько повторов на одну запись { someoperation(); recordinsertlist.ins(); } recordinsertlist.insertdatabse(); } ??? Как показывает опыт, проигрыш X++ по сравнению с чистым T-SQL конечно же бесспорный, но не настолько катастрофичный, что бы пренебречь высокоуровневой средой ![]() Job - задача одного-двух использований? Тогда наверняка есть верхняя грань приемлемости времени выполнения Job'а. Не нужен 100% оптимальный результат, достаточно достичь указанной величины. Оптимизируя 20% кода можно достичь 80% возможной оптимальности, imho ![]() Кстати, для меня сюрпризом были, что запрос из while select исполняется по мере выполнения цикла (если верить систем монитору). Собственно селект занимает пару минут, не больше. Возможно, есть способ заставить выполнить весь запрос (т.е. набрать рекордсет), а потом по нему производить операции? Насчет приемлимости - да, операция нечастая, и в принципе приемлема, но клиент готов платить если улучшение будет раза в два... Высокоуровневой средой можно пожерствовать, посколку код не универсален, а под одного клиента, ну и в подзабтом SQL поупражняться  
		
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#7 | 
| 
			
			 злыдень 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
Управление опциями SQL запроса 
				__________________ 
		
		
		
		
	Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/  | 
| 
	
 | 
| 
			
			 | 
		#8 | 
| 
			
			 ---------------- 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Есть простой способ. 
		
		
		
		
		
		
		
		
			Надо сделать вставку recordinsertlist.insertdatabse(); в несколько раз реже, чтобы запихивалась не 1-10 записей а сразу 1000-2000. Цитата: 
	
		
			для меня сюрпризом были, что запрос из while select исполняется по мере выполнения цикла
		
	 
Последний раз редактировалось Wamr; 27.12.2006 в 17:21.  | 
| 
	
 | 
| 
			
			 | 
		#9 | 
| 
			
			 NavAx 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
3 строки в секунду? Что-то очень медленно, через COM с такой скоростью грузится. Что именно там происходит? 
				__________________ 
		
		
		
		
	Isn't it nice when things just work?  | 
| 
	
 | 
| 
			
			 | 
		#10 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
		
			Сообщение от glibs
			 
 
			Значит смотрите. Есть два подхода решения проблемы: 
		
	1. Лбом сквозь стену. 2. Рациональный. Первый психологически проще. Можно и прямой запрос написать, и в Аксапте что-то делать. Второй предполагает выработку оптимального решения. Вы говорите, что у вас за 1 000 000 проводок. Кто-то их поштучно просматривает? Они действительно нужны? М.б. можно свернутые сделать? И как вы их анализируете? М.б. их в OLAP можно перенести? Ну и т.д.   ). Бизнес логику я все же не сильно понимаю и вижу только чаасть процесса, поэтому приходиться оптимизировать то, что есть.Цитата: 
	
		
			Сообщение от glibs
			 
 
			Если решать в лоб, то сравните скорость отработки вашего джоба, но с полностью закомментированной вставкой. Причем в одном случае это делайте в транзакции, а во втором не в транзакции. Из разницы во времени вы поймете грубоватую оценку того, сколько времени уходит на чтение, сколько на вставку, и сколько на блокировки. 
		
	Предположительно, у вас тормозит вставка. Потом посмотрите, в какую таблицу вы пишете. Там есть индексы (особенно кластерные)?   Возможно, вы правы. Хотя по профайлеру физическая вставка РекордИнсертЛист.InsertDatbase() не так много занимает. Пытался проанализировать с помощью профайлера но на количестве записей большем чем 500 ну оооочень долго делает. И, как мне показалось, не совсем адекватные результаты иногда дает, нелогичные. - 56% - собственно запрос while select (хотя если отдельно запустить, без while - исполняется очень бысто) - 33% - операции над каждой записью, в том числе создание добавление єлемента РекордИнсертЛист - вставка где-то в оставшихся % За идеи спасибо! 
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#11 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#12 | 
| 
			
			 NavAx 
		
			
	 | 
	
	
	
		
		
		
		 
			
			 Кластерный индекс на той таблице, которую заполняете?
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	Isn't it nice when things just work?  | 
| 
	
 | 
| 
			
			 | 
		#13 | 
| 
			
			 ---------------- 
		
			
	 | 
	
	
	
		
		
		
		 
			
			while selec a join b join c 
		
		
		
		
		
		
		
	У вас используются все поля из 3х таблиц? Если нет, то лучше их указать в запросе  | 
| 
	
 | 
|
| За это сообщение автора поблагодарили: Oleksandr (1). | |
| 
			
			 | 
		#14 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
Цитата: 
	
Систем монитор, кстати, говорить что количество селектов соотв. количеству записей... Код:     AgreementTable      agreementTable;
    ContractTable       contractTable;
    ContractPartTable   contractPartTable;
    ;
    prognosisLineList   = new RecordInsertList(tablenum(PrognosisLines));
    prognosisList       = new RecordSortedList(tablenum(PrognosisLines));
    prognosisList.sortOrder(fieldnum(PrognosisLines, PrognosisId),
                            fieldnum(PrognosisLines, AgreementNum),
                            fieldnum(PrognosisLines, ProductNum),
                            fieldnum(PrognosisLines, StartDate),
                            fieldnum(PrognosisLines, YearMonth));
    ttsbegin;
    while select agreementTable
        where agreementTable.DeliveryCategory           == deliveryCategory
        join contractTable
            where contractTable.DeliveryCategory        == agreementTable.DeliveryCategory
                 ---
            join contractPartTable
                where contractPartTable.ContractNum     == contractTable.ContractNum
                 ---
                     {
        this.writePrognosisLines(agreementTable,
                                 contractTable,
                                 contractPartTable); // опрерации + вставка
    }
    prognosisLineList.insertDatabase();
    this.prognosisTotals();
    ttscommit;
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#15 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Да, причем сложный, и это нехорошо, без него попробую
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#16 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 
			
			Многие. Но в принципе может быть поиожет, таблички нелегкие, почему-то сразу не подумал об этом.
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#17 | 
| 
			
			 NavAx 
		
			
	 | 
	
	
	
		
		
		
		 
			
			а что с памятью творится? prognosisLineList на миллион записей не начинает на диск кэшироваться?
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	Isn't it nice when things just work?  | 
| 
	
 | 
| 
			
			 | 
		#18 | 
| 
			
			 ---------------- 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
		
			Систем монитор, кстати, говорит что количество селектов соотв. количеству записей...
		
	 
 | 
| 
	
 | 
| 
			
			 | 
		#19 | 
| 
			
			 Участник 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
В общем много неизвестных, и эксперименты слишком долгие получаются чтоб ынормально проанализировать.. С профайлером вообще нереально на больших данных. Вот и хотел сравнить с чисто сиквельным решением. Ладно, всем спасибо за советы, попробую поэксперементировать еще, сообщу 
				__________________ 
		
		
		
		
	-- regards, Oleksandr  | 
| 
	
 | 
| 
			
			 | 
		#20 | 
| 
			
			 Member 
		
			
	 | 
	
	
	
		
		
		
		 Цитата: 
	
		
			Сообщение от Oleksandr
			
			 
... 
		
	Да, индексы есть, два, каждый из 5 полей, оба уникальных, и кластерный.   ... Вариант оптимизации — писать в таблицу без индексов, потом копировать в таблицу с индексами. Здесь можно применить и прямой SQL (с RecId уже проблем не будет). Но это очень жесткий (я бы сказал экстремальный) метод. Цитата: 
	
		
			Сообщение от Oleksandr
			
			 
... 
		
	Хотя по профайлеру физическая вставка РекордИнсертЛист.InsertDatbase() не так много занимает. Пытался проанализировать с помощью профайлера но на количестве записей большем чем 500 ну оооочень долго делает. И, как мне показалось, не совсем адекватные результаты иногда дает, нелогичные. - 56% - собственно запрос while select (хотя если отдельно запустить, без while - исполняется очень бысто) - 33% - операции над каждой записью, в том числе создание добавление єлемента РекордИнсертЛист - вставка где-то в оставшихся % ... Так все-таки, если отказаться от вставки — т.е. прогнать скрипт вхолостую — сколько времени уйдет? Просто секундомером замерить нужно без профайлера. Т.е. закоментарьте строчки ttsbegin; this.writePrognosisLines... prognosisLineList.insertDatabase(); this.prognosisTotals(); ttscommit; Если будет долго, то бросайте. Нужно будет разбирать сам select. 
				__________________ 
		
		
		
		
	С уважением, glibs®  | 
| 
	
 | 
| 
	
	 | 
	
		
		
  |