Ускоряем ЗУП 3 Корп на предприятиях с большим количеством работников

15.03.24

База данных - HighLoad оптимизация

Как только мы перешли с УПП на ЗУП 3, сразу столкнулись с огромной проблемой. Наша организация в 12 000 человек, разбив документы на 2 части по 6 000 человек не смогла за несколько часов рассчитать зарплату, и пришлось срочно заниматься оптимизацией "на ходу". В процессе выяснилось немало ключевых мест, и в результате, как правило, небольшими "инъекциями", удалось качественно (часть участков с часов до минут, а местами и до секунд) ускорить процесс и дать возможность расчетчикам выполнять работу в сжатые сроки. В результате этого процесса получилось расширение. Которое можно просто применить на типовой ЗУП Корп.  Если будет потребность для адаптации под конкретный релиз пишите, сделаем.

Скачать исходный код

Наименование Файл Версия Размер
Ускоряем ЗУП 3 Корп на предприятиях с большим количеством работников:
.cfe 911,03Kb
2
.cfe 911,03Kb 2 Скачать
Ускоряем типовой ЗУП 3 Корп (для 3.1.25.40, 3.1.25.136)
.cfe 93,46Kb
11
.cfe 93,46Kb 11 Скачать

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

К "классическим" можно отнести достаточно типовые варианты, которые типовая ЗУП нередко игнорирует, но которые сильно проявляют себя при увеличении объема данных (геометрическая прогрессия) и при использовании RLS.

  1. Добавление индекса в запросы
  2. Добавление индекса в таблицы значений для ускорения поиска в коде 1С
  3. "Выбрать различные". Казалось бы, неэффективный способ, но по практике есть места в запросах, которые возвращают большое количество дублей в промежуточных таблицах, и в последующих запросах возникает излишний перебор.
  4. "Предотбор" элементов в "где". Особенно эффективно это когда меняем отбор для  "разыменования"

И был найден очень "безобидный" кусок в очередном релизе ЗУП

Общий модуль УчетСреднегоЗаработка

	ИсключаемыеСтроки = Новый Массив;
	Для Каждого СтрокаНачислений Из Начисления Цикл 
		Если ИсключаемыеСтроки.Найти(СтрокаНачислений) <> Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		Для Каждого ТекущаяСтрока Из Начисления Цикл
			Если СтрокаНачислений = ТекущаяСтрока Тогда
				Продолжить;
			КонецЕсли;
			Если ИсключаемыеСтроки.Найти(ТекущаяСтрока) <> Неопределено Тогда 
				Продолжить;
			КонецЕсли;
			ЗначенияКолонокСовпадают = Истина;
			Для Каждого ИмяКолонки Из ИменаКолонок Цикл 
				Если СтрокаНачислений[ИмяКолонки] <> ТекущаяСтрока[ИмяКолонки] Тогда
					ЗначенияКолонокСовпадают = Ложь;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			Если Не ЗначенияКолонокСовпадают Тогда 
				Продолжить;
			КонецЕсли;
			Если СтрокаНачислений.Сумма = -ТекущаяСтрока.Сумма Тогда 
				ИсключаемыеСтроки.Добавить(СтрокаНачислений);
				ИсключаемыеСтроки.Добавить(ТекущаяСтрока);
				Прервать;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	ИсключаемыеНачисления = Начисления.Скопировать(ИсключаемыеСтроки);
	Для Каждого ИсключаемаяСтрока Из ИсключаемыеСтроки Цикл 
		Начисления.Удалить(ИсключаемаяСтрока);
	КонецЦикла;
	

В результате запуска профайлера выяснилось, что данный кусок кода для 6 000 сотрудников работает порядка 4 часов.

Потому что в начислений "всего" порядка 138 000 строк, и десяток колонок.

Но данный код геометрически увеличил циклы до миллиардов итераций.

Переделал этот кусок на генерацию запрос скуля.

	Запрос.УстановитьПараметр("Начисления",Начисления);
	Запрос.Текст="ВЫБРАТЬ Начисления.Сумма как Сумма,Начисления.Сторно как Сторно";
	Для Каждого ИмяКолонки Из ИменаКолонок Цикл 
			Запрос.Текст=Запрос.Текст+", 
				|Начисления."+ИмяКолонки+" как "+ИмяКолонки;
	КонецЦикла;		
	Запрос.Текст=Запрос.Текст+"
	|Поместить ВТ_Начисления 
	|из &Начисления как Начисления;
	|
	| Выбрать 
	|	Сумма(Начисления.Сумма) как Сумма";
	Для Каждого ИмяКолонки Из ИменаКолонок Цикл 
			Запрос.Текст=Запрос.Текст+",
				|Начисления."+ИмяКолонки+" как "+ИмяКолонки;
	КонецЦикла;		
	Запрос.Текст=Запрос.Текст+"
	|Поместить ВТ_ИсключаемыеСтроки 
	|	из ВТ_Начисления как Начисления
	|	Сгруппировать по 1";
	Для Каждого ИмяКолонки Из ИменаКолонок Цикл 
			Запрос.Текст=Запрос.Текст+",
				|Начисления."+ИмяКолонки;
	КонецЦикла;		
	Запрос.Текст=Запрос.Текст+"
	| Имеющие Сумма(Начисления.Сумма)=0
	|	;
	|
	|	ВЫБРАТЬ Начисления.Сумма как Сумма,Начисления.Сторно как Сторно";
	Для Каждого ИмяКолонки Из ИменаКолонок Цикл 
			Запрос.Текст=Запрос.Текст+", 
				|Начисления."+ИмяКолонки+" как "+ИмяКолонки;
	КонецЦикла;		
	Запрос.Текст=Запрос.Текст+"
	|	из ВТ_Начисления как Начисления
	|	Левое соединение
	|	 ВТ_ИсключаемыеСтроки как ВТ_ИсключаемыеСтроки
	|   по Истина ";
	Для Каждого ИмяКолонки Из ИменаКолонок Цикл 
			Запрос.Текст=Запрос.Текст+" и 
				|Начисления."+ИмяКолонки+" = ВТ_ИсключаемыеСтроки."+ИмяКолонки;
	КонецЦикла;		
	Запрос.Текст=Запрос.Текст+"
	|	где ВТ_ИсключаемыеСтроки."+ИмяКолонки+" есть NULL;
	|
	| Выбрать * из ВТ_ИсключаемыеСтроки;";
	Пакет = Запрос.ВыполнитьПакет();
	Начисления = Пакет[2].Выгрузить(); 
	ИсключаемыеНачисления = Пакет[3].Выгрузить();

В итоге вся работа происходит за считанные секунды.

Проверено на релизах ЗУП КОРП 3.1.25.40 и 3.1.25.136

 

PS.

Вполне вероятно будет работать и на ERP 2, в связи с тем что внутри ерп модули ЗУП 3 корп

 

Очередное ускорение

под новые релизы ЗУП

Выявил новое место

на нашем примере - часть сотрудников -пачка в 4000 человек

расчет рабочих дней

запрос шел более часа

анализ показал что мало того что там 5 соединений

но самое "страшное"
3 соединения

по каждому сотруднику строчки по дням 

итого 30 строк по каждому в первой

во второй периоды действия графика -тоже сделано 30 строк, хотя периоды одинаковые и строки одинаковые

в третьей таблице - периоды состояний такая же ситуация -30 дублей строк

в итоге идет свертка до 30 строк -сотрудник, дата, итог

 

но "внутри" запроса SQL приходится сначала делать огромную таблицу

30*30*30 = 27 000 на каждого сотрудника!

для наших 4 000 - это более 100 000 000 строк в темпбд

и потом сворачивать их...

 

добавление индексов и убирание лишних дублей позволило запрос ускорить

с 3217 сек до 12 сек

Проверено на следующих конфигурациях и релизах:

  • Зарплата и управление персоналом, редакция 3.1, релизы 3.1.27.193, 3.1.25.136

ЗУП3 ускорение оптимизация

См. также

Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы

HighLoad оптимизация Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    3644    spyke    28    

47

Быстродействие типовой 1С

HighLoad оптимизация Платформа 1С v8.3 Бесплатно (free)

Оказывается, в типовых конфигурациях 1С есть, что улучшить!

13.03.2024    5623    vasilev2015    19    

38

Анализируем SQL сервер глазами 1С-ника

HighLoad оптимизация Инструменты администратора БД Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих зааросов на sql, ожиданий, конвертация запроса в 1с и рекомендации где может тормозить

1 стартмани

15.02.2024    8504    170    ZAOSTG    74    

102

Удаление строк из таблицы значений различными способами с замером производительности

HighLoad оптимизация Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Встал вопрос: как быстро удалить строки из ТЗ? Рассмотрел пять вариантов реализации этой задачи. Сравнил их друг с другом на разных объёмах данных с разным процентом удаляемых строк. Также сравнил с выгрузкой с отбором по структуре.

09.01.2024    6812    doom2good    49    

65

Опыт оптимизации 1С на PostgreSQL

HighLoad оптимизация Бесплатно (free)

При переводе типовой конфигурации 1C ERP/УТ/КА на PostgreSQL придется вложить ресурсы в доработку и оптимизацию запросов. Расскажем, на что обратить внимание при потерях производительности и какие инструменты/подходы помогут расследовать проблемы после перехода.

20.11.2023    9597    ivanov660    6    

76

ТОП проблем/задач у владельцев КОРП лицензий 1С на основе опыта РКЛ

HighLoad оптимизация Бесплатно (free)

Казалось бы, КОРП-системы должны быть устойчивы, быстры и надёжны. Но, работая в рамках РКЛ, мы видим немного другую картину. Об основных болевых точках КОРП-систем и подходах к их решению пойдет речь в статье.

15.11.2023    5440    a.doroshkevich    20    

72

Начните уже использовать хранилище запросов

HighLoad оптимизация Запросы

Очень немногие из тех, кто занимается поддержкой MS SQL, работают с хранилищем запросов. А ведь хранилище запросов – это очень удобный, мощный и, главное, бесплатный инструмент, позволяющий быстро найти и локализовать проблему производительности и потребления ресурсов запросами. В статье расскажем о том, как использовать хранилище запросов в MS SQL и какие плюсы и минусы у него есть.

11.10.2023    16714    skovpin_sa    14    

101
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. user1175436 25 10.05.23 14:45 Сейчас в теме
добрый день!

1500 сотрудников - без расширения начисление ЗП заполняется за 1 минуту , а с расширением - 1 минута 20 секунд
2. ZAOSTG 143 10.05.23 21:15 Сейчас в теме
(1)Странно очень. Профайлер есть?
3. Gesperid 2 11.05.23 11:42 Сейчас в теме
Ваш запрос делает не то, что код.
Например, в такой таблице:
ИдентификаторСтроки Сумма
84 -168
84 168
84 -190

Запрос ничего не удалит, а код удалит две первые строки.
Я бы начал с индексации таблиц.
	//+
	ИменаКолонокСтрокой = СтрСоединить(ИменаКолонок, ",");
	Начисления.Индексы.Добавить(ИменаКолонокСтрокой);

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

		Если ИсключаемыеСтроки.Найти(СтрокаНачислений) <> Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		
		Для Каждого ТекущаяСтрока Из Начисления Цикл 
			Если СтрокаНачислений = ТекущаяСтрока Тогда
				Продолжить;
			КонецЕсли;  
			
			Если ИсключаемыеСтроки.Найти(ТекущаяСтрока) <> Неопределено Тогда
				Продолжить;
			КонецЕсли;  
			
			//
			ЗначенияКолонокСовпадают = Истина;
			Для Каждого ИмяКолонки Из ИменаКолонок Цикл 
				Если СтрокаНачислений[ИмяКолонки] <> ТекущаяСтрока[ИмяКолонки] Тогда
					ЗначенияКолонокСовпадают = Ложь;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			Если Не ЗначенияКолонокСовпадают Тогда 
				Продолжить;
			КонецЕсли;
			
			//
			Если СтрокаНачислений.Сумма = -ТекущаяСтрока.Сумма Тогда 
				ИсключаемыеСтроки.Добавить(СтрокаНачислений);
				ИсключаемыеСтроки.Добавить(ТекущаяСтрока);
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
	КонецЦикла;
	
	//+
	Для каждого КлючЗначение Из ИсключаемыеСтрокиСоответствие Цикл
		ИсключаемыеСтроки.Добавить(КлючЗначение.Ключ);
	КонецЦикла;
	//-
Показать
4. ZAOSTG 143 22.05.23 12:08 Сейчас в теме
(3)Согласен, запрос может пропустить часть данных для сворачивания
Но думаю что предложенная Вами ситуация в основном искусственная - отсторнировали и снова сделали запись
Ради таких "пропусков", делающих излишние проверки далее, жертвовать часы работы "оригинал" или "переделка" мы выбрали переделка

Ваш вариант кода тестирую на наших данных. Если поможет -огромное спасибо за совет, помещу в расширение
cleaner_it; +1 Ответить
5. Kesak 14 25.05.23 00:19 Сейчас в теме
(4) Тестирование ещё в процессе?
6. ZAOSTG 143 25.05.23 05:58 Сейчас в теме
(5)Так как код - часть, и не взлетел с ходу, потому что ИсключаемыеСтроки определяются ниже, а тут уже ищутся, не успел -завал. В рабочей уже несколько месяцев используют запрос -замечаний нет
7. artbear 1528 03.06.23 12:58 Сейчас в теме
(3) Ага, хороший вариант, но не хватает поиска в таблице по сумме, ведь она заранее известна!
плюс структуру КлючСтроки не нужно создавать каждый раз.

в итоге код становится практическим линейным

мой вариант
ИменаКолонокСтрокой = СтрСоединить(ИменаКолонок, ",");
ИменаКолонокСтрокой = ИменаКолонокСтрокой + ",Сумма";

Начисления.Индексы.Добавить(ИменаКолонокСтрокой);

ИсключаемыеСтрокиСоответствие = Новый Соответствие;
КлючСтроки = Новый Структура(ИменаКолонокСтрокой);

Для Каждого СтрокаНачислений Из Начисления Цикл
	
	Если ИсключаемыеСтрокиСоответствие[СтрокаНачислений] <> Неопределено Тогда 
		Продолжить;
	КонецЕсли;
	
	ЗаполнитьЗначенияСвойств(КлючСтроки, СтрокаНачислений);
	КлючСтроки.Сумма = -СтрокаПотенциальная.Сумма;
	
	ИсключатьСтроку = Ложь;
	Для каждого СтрокаПотенциальная Из Начисления.НайтиСтроки(КлючСтроки) Цикл 
		ИсключатьСтроку = Истина;
		Если ИсключаемыеСтрокиСоответствие[СтрокаПотенциальная] = Неопределено Тогда
			ИсключаемыеСтрокиСоответствие.Вставить(СтрокаПотенциальная);
			ИсключаемыеСтроки.Добавить(СтрокаПотенциальная);
		КонецЕсли;
	КонецЦикла;    
	Если ИсключатьСтроку Тогда      
		ИсключаемыеСтрокиСоответствие.Вставить(СтрокаНачислений);
		ИсключаемыеСтроки.Добавить(СтрокаНачислений);
	КонецЕсли;
КонецЦикла;
Показать
8. ZAOSTG 143 06.06.23 15:32 Сейчас в теме
Кстати
в релиз 3.1.25.136 1С снова подложили pork насчет производительности
сейчас доделываю обработку по подготовке регистров и в расширение добавлю ускорение
регистры по отпускам и аналитикам затрат - страшно медленно -на нашей базе это более 7 часов обработка первой части
и десяток часов когда пользователям уже можно работать...
9. ILM 240 08.06.23 10:58 Сейчас в теме
Валентин, напишите как с УПП переходили?
10. ZAOSTG 143 11.06.23 20:05 Сейчас в теме
(9)Мучительно ;)
1 - различное хранение данных. В ЗУП сделали "гениальную" реализацию - в один день можно сделать несколько кадровых операций. Добавляют секунду. в УПП такого нельзя. в итоге пришлось танцевать с бубном чтобы в УПП кадровая история
2 - обмены. как с кадровыми так и ведомости. Аналитика разрозненная, трансформации,
3 -скорость обмена. у нас ведомости на 6 000 чел уходя часами -механизм кривоватый, "дубовый" -пришлось его срочно ускорять

Перешли на ЗУП потому что "голова" решила что "будет как у нас!" Но одно дело офисный планкттон с его расчетом зп, другое строительная организация...
Оставьте свое сообщение