Как ускорить работу с деревом значений?

Версия для печатиPDF-версия

Как упоминал в прошлых вопросах,

 

http://novichok1c.ru/vopros/kak-programmno-dobavit-kolonki-i-ne-poteryat-nastroyki-kolonok-sozdannyh-v-tablichnom-pole

 

http://novichok1c.ru/vopros/kak-sortirovat-kolonki-tablic

 

 Я создаю инструмент (уже создал) который представляет из себя обработку на форме которой табличное поле с деревом значений.

В дерево выгружаются список поставщиков (наименование контрагента) отобранные запросом.

В подчиненные строки заливаются заказы поставщиков, которые необходимо закупить.

 

Ну и соответственно в колонки выводится масса дополнительных и штатных реквизитов.

 

По окончании «сборки» обработки продукт получился хотя и рабочий, но не жизнеспособный (первая версия).

1.       Заполнялся по 3 минуты.

Опытным путем пришел к тому, что заполнять запросами, очень долго, поэтому запросом беру все заказы за больший период, чем необходимо (на всякий случай), выгружаю в Тз и уже в ней циклом произвожу поиски и сортировки.

Тем более когда речь пошла о РегистрНакопления.РасчетыСКонтрагентами.

По окончании манипуляций с таблицами, таблицы очищаю.

 

В итоге время загрузки сократилось от 1 до 5 секунд.

 

2.       При количестве строк от 300 и выше начинаются тормоза, чтобы включить флажок, проходит почти секунда, иногда значительно больше…   

Тут ничего придумать не могу…((((

 

Из всего эксперимента работы с деревом у меня есть ряд вопросов:

 

Некоторые таблицы для упрощения кода, пришлось разместить в реквизиты формы.

Таблицы в реквизитах формы, очищенные, сильно замедляют работу?

(Ну, просто их наличие…)

 

 

 

Есть возможность не только очищать, но Удалять Тз ?

 

Есть возможность у платформы как-то кэшировать Дерево значений?  Я где-то натыкался на некое Соответствие , но пока не понимаю, как этим пользоваться…(((

1. Мне кажется, что у вас заполнение дерева неоптимизировано. По идее, надо все данные получать одним запросом и сразу выгружать эти данные в дерево значений. Тогда необходимость дополнительных таблиц отпадёт. Какие промежуточные данные хранятся во вспомогательных таблицах?

2. У поля с флажком обработчика ПриИзменении не прописано?

3. Таблицы в реквизитах формы не должны влиять на скорость работы.

4. Удалять можно только динамически создаваемые ТЗ. Если ТЗ - это реквизит формы, то её удалить нельзя.

5. Для каких целей хотите кэшировать дерево значений? Соответствие можно использовать для кэширования значений, но это используется, например, при многократном поиске значений справочника по наименованию. Не знаю, как можно использовать кэширование для дерева значений.

1. Использую 3 запроса. Данные в одном вношу в Таблицу значений (реквизит формы)
В двух других в Тз.
Затем двумя циклами дополняю значениями первую (с соответствующим добавлением колонок)
После чего очищаю обе Тз
 
Так же использую дополнительную (промежуточную) Тз. В которую копирую содержание первой (основной таблицы) Сворачиваю по контрагенту, чтобы не было повторений, на базе ее делаю строки родителя в дереве, затем добавляю подчиненные строки из основной таблицы.
 
После заполнения дерева, все таблицы очищаются
 
Заполнять таблицы из запроса, например, циклом выборки – очень долго, циклы между таблиц побили результаты…
 
Смонтировать один работоспособный запрос, в том числе вложенные, или Обеднённый, не получилось.
Вероятно, попрошу у Вас совета при отладки в следующую версию.
 
Но заполняет быстро.
 
А вот работает медленно.
 
2. ПриИзменении  - не использую, использую при ПриИзмененииФлажка.

Процедура ТаблицаПриИзмененииФлажка(Элемент, Колонка)
	
			УстанавливаемоеЗначение = Элемент.ТекущаяСтрока.Вкл;
		
		Если Элемент.ТекущаяСтрока.Родитель = Неопределено Тогда
				КолЭлементов = Элемент.ТекущаяСтрока.Строки;
			Для каждого СтрокаЭлемента из КолЭлементов Цикл
				СтрокаЭлемента.Вкл = УстанавливаемоеЗначение;
				СтрокаЭлемента.Он = УстанавливаемоеЗначение;
			
			КонецЦикла;
		Иначе 
			
				Элемент.ТекущаяСтрока.Он = УстанавливаемоеЗначение;
		КонецЕсли;
				
		ПодключитьОбработчикОжидания("ОбновитьСодержимое", 1, Истина);		
КонецПроцедуры



//Отражение И подсчет Сумм подвалов и колонок
Процедура ОбновитьСодержимое()
	
	Для Каждого Колонка Из ДеревоЗначенийЗаказов.Колонки Цикл 
		   		 ИмяКолонка = Колонка.Имя;
				 
		Если Колонка.ТипЗначения.СодержитТип(Тип("Число")) Тогда
					СуммаКолонки = 0;
					
			Для каждого СтрТЗ Из ДеревоЗначенийЗаказов.Строки Цикл
				
				Если СтрТЗ.Он = Истина И ЗначениеЗаполнено(СтрТЗ.Контрагент) И ТипЗнч(СтрТЗ.Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда 		
								 РассчитатьОбщуюСтоимостьКолонок(СтрТЗ, ИмяКолонка );  
				КонецЕсли;						
				
				Для Каждого СтрокаУ Из СтрТЗ.Строки Цикл
					
					Если СтрокаУ.Он = Истина Тогда 
						мДанные =  СтрокаУ[ИмяКолонка];
						СуммаКолонки = СуммаКолонки + мДанные;
					КонецЕсли;
					   
		    	КонецЦикла;
				
			КонецЦикла; 
			   	СовпадающаяКолонка = ЭлементыФормы.ТаблицаДереваЗначенийЗаказов.Колонки.Найти(ИмяКолонка);
				Если СовпадающаяКолонка <> Неопределено И СовпадающаяКолонка.Видимость = Истина Тогда 
					СовпадающаяКолонка.ОтображатьВПодвале = Истина;				
					СовпадающаяКолонка.ТекстПодвала = СуммаКолонки;
				КонецЕсли;
		КонецЕсли;
		
		
		
	КонецЦикла;
	
	
	

КонецПроцедуры
Как видите, даже обновление вывел, в обработку ожидания, чтобы она срабатывала с опозданием, после всех манипуляций с галочками.
А вот переключает галочки медленно.
Разворачивает и сворачивает вкладку ( иерархия один вложенный уровень, или как это называется? В сроке Контрагент, вложен уровень со строками ЗаказовПоставщику.
 
 

 

4. Научите, пожалуйста удалять Тз. Я не нашел как это делать.
Читал, что для лучшего освобождения оперативки, массивы нужно пересоздавать, а не очищать.
 
А как удалять Тз или Массивы – не нашел…
 
5. Если не возражает, про кэширование я в отдельной теме задам вопрос. Дабы не смешивать темы. Очень интересно. Но инфо, которое пытался найти, весьма скудно. Натыкался на код, в обработках, которые исследовал, а иногда перерабатывал, и хотя использую ( в них же), но не догоняю как и что…
 
Заполняю Так:

Процедура ИзТзВДерево()
	
		
				
		СписокПоставщиков = Новый Массив;

	Для Каждого СтрокаПоставщик Из ТаблицаЗначенийПоставщики Цикл
		СписокПоставщиков.Добавить(СтрокаПоставщик.Контрагент.Ссылка);
	КонецЦикла;
	
			ТаблицаЗначенийПоставщики.Очистить();

	
	СписокЗаказов = Новый Массив;
	
	Для Каждого СтрокаТабР Из ТаблицаРезультат Цикл
		СписокЗаказов.Добавить(СтрокаТабР);
	
	КонецЦикла;
	

	
	Для Каждого СтрокаПоставщик Из СписокПоставщиков Цикл
		

		
		
		НовыйПоставщик = ЭлементыФормы.ТаблицаДереваЗначенийЗаказов.Значение.Строки.Добавить(); //  ДеревоЗначенийЗаказов.Строки.Добавить();

		НовыйПоставщик.Контрагент = СтрокаПоставщик.Ссылка;
		НовыйПоставщик.Вкл = Истина;
		НовыйПоставщик.Он  = Истина;
		НовыйПоставщик.ДатаПоcтупления = "";
		НовыйПоставщик.Сшит = Ложь;		
		
	Для Каждого ТекЗаказ ИЗ СписокЗаказов Цикл
			
		Если ТекЗаказ.Контрагент = СтрокаПоставщик Тогда
					
				НовыйЗаказПоставщика = НовыйПоставщик.Строки.Добавить();
				
	            НовыйЗаказПоставщика.Он  = Истина;
				НовыйЗаказПоставщика.Вкл = Истина;
				НовыйЗаказПоставщика.Сшит = Ложь;
				НовыйЗаказПоставщика.Контрагент = ТекЗаказ.Ссылка;

				
				НовыйЗаказПоставщика.Сумма = ТекЗаказ.СуммаДокумента;
				НовыйЗаказПоставщика.ДатаПоcтупления = ТекЗаказ.ДатаПоступления;				
				НовыйЗаказПоставщика.Количество = "1";   //ТекЗаказ.Товары.Количество();
				
				НовыйЗаказПоставщика.Комментарий     = ТекЗаказ.Комментарий;
				
				НовыйЗаказПоставщика.Предоплата = ТекЗаказ.Платеж;
				НовыйЗаказПоставщика.ПоследняяПоставка = ТекЗаказ.ДатаПоследнего;
				
				мДатаПоступления = СтрЗаменить(Формат(ТекЗаказ.ДатаПоступления, "ДЛФ=D" ),".","");
				мДатаПоступления = СтрЗаменить(мДатаПоступления," ","");
				мИмяКолонкиК = "К" + мДатаПоступления + "";			
				мИмяКолонкиС = "С" + мДатаПоступления + "";
				мИмяКолонкиД = "Д" + мДатаПоступления + "";	
				
				
				
				
				Попытка
					РфЧисло = ТекЗаказ.СуммаДокумента;
					НовыйЗаказПоставщика[мИмяКолонкиС] = РфЧисло;
					
										НовыйЗаказПоставщика[мИмяКолонкиК] = НовыйЗаказПоставщика.Количество;
					
					
						
					ЭлементыФормы.ТаблицаДереваЗначенийЗаказов.Колонки[мИмяКолонкиК].Видимость = Истина;
					ЭлементыФормы.ТаблицаДереваЗначенийЗаказов.Колонки[мИмяКолонкиС].Видимость = Истина;
					ЭлементыФормы.ТаблицаДереваЗначенийЗаказов.Колонки[мИмяКолонкиД].Видимость = Истина;
					
					
				Исключение
					Сообщить(ОписаниеОшибки());
				КонецПопытки;

			КонецЕсли;	
			
		КонецЦикла;	
		
		
	КонецЦикла;
	

		ТаблицаРезультат.Очистить();	

	
		
	
КонецПроцедуры
 

Обратил внимание вот на что:

Когда форма обработки открыта, просто открыта, без активных действий (вхолостую), то по Диспетчеру задач винды видно, что одно ядро нагружается, почти полностью, причем как на 4х ядерном, так и на двухядерном, а вот оперативки совсем не много отъедает...

(относительно не много, от 200, до 500 Мб)

Попробовал переметить форму обработки в документ, в надежде, что платформа по разному ресурсы расскидывает. Но результат тот же.

 

 

1. Мне всё равно непонятно, зачем создавать несколько таблиц, заполнять их данными из разных запросов, а потом в цикле их как-то обрабатывать. Нужно постарваться сделать это всё одним запросом. В частности, так называемую иерархию по контрагенту можно сделать при помощи итогов (просто в запросе добавить ИТОГИ ПО Контрагент). После этого можно результат запроса сразу выгрузить в дерево значений:

ДЗ = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

2. По поводу медленной работы. Посмотрите отладчиком, что происходит при изменении флажка. Включите замер производительности (в конфигураторе меню Отладка - Замер производительности). Увидите, на какие действия большая часть времени затрачивается.

4. Если массив или таблица значений созданы динамически, то для удаления данных (очистки памяти) достаточно присвоить переменной значение Неопределено.

Нашел причину.

Оказалось, что дерево значений чувствительно к оформлению строк родителей в ПриВыводеСтроки.

Перенес оформление родителей в ПриПолученииДанных и нагрузка на процессор мгновенно снизилась в несколько раз…