gifts2017

Разгон РАУЗ в 1С УПП 1.3 (платформа 8.2)

Опубликовал Дмитрий Соколов (DNSokol) в раздел Обработки - Закрытие периода

В статье рассматривается вопрос повышения быстродействия расчета себестоимости в конфигурации 1С УПП 1.3 при включенном режиме РАУЗ и наличии большого количества материальных затрат. Глубокого погружения в теорию тут ждать не стоит, для этого есть другие хорошо написанные книги и статьи. Тут будет рассмотрен метод "по быстрому".

Итак, есть УПП версии 1.3, включенный РАУЗ и печальный факт того, что расчет себестоимости выполняется от двух часов и более. Ну и "бешенные" пользователи, которые "для проверки" запускают расчет себестоимости в конце/начеле месяца более чем часто.

Прежде чем бежать за новым железом (которое в общем и целом не виновато) и прежде чем уходить с головой в изучение индексов СУБД, можно немного оптимизировать код УПП, который позволит существенно поднять производительность.

Итак, не погружаясь особо в дебри теории, просто примем за аксиому, что последовательность измерений независимого (без регистратора) регистра сведений влияет на то, как в конечном счете будут построены индексы SQL. При включенном РАУЗ и большом количестве материальных затрат используется регистр сведений "АналитикаУчетаПартий". Измерения "из коробки" выглядят следующим образом:

 Типовая последовательность измерений РС АналитикаУчетаПартий

Если посмотреть в базу УПП и проанализировать содержимое регистра (это для моего конкретного случая, у кого-то может быть другая картина заполнения), то видно, что 80% содержания регистра занимают вот такие вот записи:

Содержимое регистра партий

 Т.е. статусы партий, заказы, договоры коминтента и т.д. не используются. Т.о. индексы которые создаются как самое 1С, так и SQL сервером в данном случае бестолковые, т.к. тратят процессорное время на то, что бы делать выборку по не заполненным полям. Поэтому, в моем случае последовательность измерений пыла переделана следующим образом:

 новая последовательность измерений

 

Ну и дополнительно по измерению "ФизЛицо" необходимо включить индексирование.  Собственно, вышеописанные действия по анализу содержимого регистров и перемещению измерений можно применить к регистрам сведений "АналитикаУчетаЗатрат" и "АналитикаВидаУчета". Единственное, что стоит помнить, это то что в регистре не стоит ставить галку "индексировать" более чем у 5 измерений (почему так - тоже лучше читать в специальных умных книжках).

Вышеописанные простые действия позволили ускорить расчет себестоимости выпуска на 20 минут. Это конечно хорошо, но, мало. Поэтому, следующим этапом будет небольшая оптимизация кода. Большая часть работы РАУЗ сосредоточена в общем модуле "РасширеннаяАналитикаУчета". Изучение работы документа "Расчет себестоимости" с включенным замером производительности показал, что очень большим тормозом (из-за большого количества вызовов) является функция "ЗаполненыНастройкиАналитикиУчета". Смотрим на содержимое функции:

Функция ЗаполненыНастройкиАналитикиУчета() 
	
	ТекстЗапроса = "
	|ВЫБРАТЬ ПЕРВЫЕ 1
	|	НастройкиАналитикиУчета.Код
	|ИЗ
	|	Справочник.НастройкиАналитикиУчета КАК НастройкиАналитикиУчета
	|ГДЕ
	|	НастройкиАналитикиУчета.УправленческийУчет
	|	ИЛИ НастройкиАналитикиУчета.РегламентированныйУчет
	|
	|";
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	РезультатЗапроса = Запрос.Выполнить();
	
	Возврат (Не РезультатЗапроса.Пустой());
	
КонецФУнкции // ЗаполненыНастройкиАналитикиУчета()

Что тут видим. у нас более 300 тыс. раз вызывается простеньких запрос к СУБД с простой выборкой. Всё это хорошо, но, это время. Нужно что-то делать. А делать мы будем повторное использование возвращаемых значений. Так же, не останавливаюсь подробно на том - что это и зачем. Можно почитать в умных книжках. Сейчас просто делаем новый общий модуль, для которого устанавливаем следуюющие свойства:

 Свойстви общего модуля

и переносим в этот модуль вышеописанную функцию (просто копипастим не забыв добавить в конец объявления процедуры директиву "экспорт"), а в типовом модуле расширенной аналитики учета делаем следующее:

Функция ЗаполненыНастройкиАналитикиУчета()
	
	Возврат РасширеннаяАналитикаУчетаПовторноеИспользование.ЗаполненыНастройкиАналитикиУчета();
	
КонецФУнкции // ЗаполненыНастройкиАналитикиУчета()

Что нам это даст? А даст очень простую вещь - обращение к СУБД будет произведено только один раз. Все остальные обращения к функции "ЗаполненыНастройкиАналитикиУчета" будут приводить к тому, что возвращаемое значение будет получаться не путем обращения к SQL базе, а из кэша сервера 1С Предприятие. Дальнейшее изучение расчета седестоимости выявило то, что повторно использовать значения можно еще для двух функций "ШаблонИзмеренийКлючаАналитики" и "ПолучитьСоздатьКлючАналитики".

Вынос указанных выше функций в повторное использование вкупе с небольшой оптимизацией регистров (суть оптимизации так же описал выше) привело к тому, что расчет себестоимости при включеном РАУЗ стал занимать не 2 часа, а 5-7 минут.

Доп. информация: оптимизировал работу на УПП 1.3.49.2.

 


 

Созданный модуль "РасширеннаяАналитикаУчетаПовторноеИспользование" имеет следующие функции (настройки модуля на картинке выше):

 

Функция ЗаполненыНастройкиАналитикиУчета() экспорт
	
	ТекстЗапроса = "
	|ВЫБРАТЬ ПЕРВЫЕ 1
	|	НастройкиАналитикиУчета.Код
	|ИЗ
	|	Справочник.НастройкиАналитикиУчета КАК НастройкиАналитикиУчета
	|ГДЕ
	|	НастройкиАналитикиУчета.УправленческийУчет
	|	ИЛИ НастройкиАналитикиУчета.РегламентированныйУчет
	|
	|";
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	РезультатЗапроса = Запрос.Выполнить();
	
	Возврат (Не РезультатЗапроса.Пустой());
	
КонецФУнкции // ЗаполненыНастройкиАналитикиУчета()

Функция ШаблонИзмеренийКлючаАналитики(ИмяРегистра) экспорт
	
	ТекстЗапроса = "
	|ВЫБРАТЬ
	|	НастройкиАналитикиУчета.УправленческийУчет КАК УпрУчет,
	|	НастройкиАналитикиУчета.РегламентированныйУчет КАК РеглУчет,
	|	НастройкиАналитикиУчета.ЗначениеПоУмолчанию КАК Значение,
	|	НастройкиАналитикиУчета.Код КАК Измерение
	|ИЗ
	|	Справочник.НастройкиАналитикиУчета КАК НастройкиАналитикиУчета
	|ГДЕ
	|	НастройкиАналитикиУчета.Родитель = &Родитель
	|	И НастройкиАналитикиУчета.Предопределенный
	|	И (Не НастройкиАналитикиУчета.ЭтоГруппа)
	|
	|УПОРЯДОЧИТЬ ПО
	|	НастройкиАналитикиУчета.Наименование
	|
	|";
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("Родитель", Справочники.НастройкиАналитикиУчета[ИмяРегистра]);
	РезультатЗапроса = Запрос.Выполнить();
	Возврат РезультатЗапроса.Выгрузить();

	
	
КонецФункции


// Экспериментальный вызов. Может так случиться, что или глюков добаваит, или 
// требуемого прироста производительности не даст. Если что, нужно отменить вызов данной процедуры
// из модуля расчиренной аналитики и раскомментироватьс тарый код и закомментировать новый.
Функция ПолучитьКлючАналитики (ИмяРегистра, СтруктураИзмерений) экспорт
	
	МенеджерЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи();
	ЗаполнитьЗначенияСвойств(МенеджерЗаписи, СтруктураИзмерений);
	
	МенеджерЗаписи.Прочитать();
	
	Если МенеджерЗаписи.Выбран() Тогда
		Возврат МенеджерЗаписи.Ссылка;
	Иначе
		Возврат неопределено;
	конецЕсли;
	
КонецФункции

 

 Измененные функции модуля "РасширеннаяАналитикаУчета"

 

Функция ЗаполненыНастройкиАналитикиУчета()
	
	// -- Begin -- Sokolov_DN -- 20141005
	// Для уменьшения тормозов: можно вызов засунуть в повторное использование и читать из кэша. 
	// Всё равно вызов непараметризуемый
	
	Возврат РасширеннаяАналитикаУчетаПовторноеИспользование.ЗаполненыНастройкиАналитикиУчета();
	
	// --  End  -- Sokolov_DN -- 20141005
	
КонецФУнкции // ЗаполненыНастройкиАналитикиУчета()

Функция ШаблонИзмеренийКлючаАналитики(
	ИмяРегистра,
	СтруктураКлючиАналитики
	)
	
	Перем ШаблонИзмерений;
	
	ИмяСтруктурыИзмерений = "Шаблон" + ИмяРегистра;
	
	Если СтруктураКлючиАналитики = Неопределено
	 ИЛИ Не СтруктураКлючиАналитики.Свойство(ИмяСтруктурыИзмерений, ШаблонИзмерений) Тогда
		
	 	Если Не ЗаполненыНастройкиАналитикиУчета() Тогда
			ЗаполнитьНастройкиАналитикиПоШаблону();
		КонецЕсли;
		
		Если ИмяРегистра = "АналитикаУчетаПрочихЗатрат" Тогда
			ШаблонИзмерений = ШаблонИзмеренийИзМакета(ИмяРегистра);
		Иначе
		
			// -- Begin -- Sokolov_DN -- 20141005
			// Для уменьшения тормозов: можно вызов засунуть в повторное использование и читать из кэша. 
			// постоянно выбираем из фиксированного справочника, поэтому лучше закэшировать и оставить базу в покое
			
			
			ШаблонИзмерений = РасширеннаяАналитикаУчетаПовторноеИспользование.ШаблонИзмеренийКлючаАналитики(ИмяРегистра);
			// --  End  -- Sokolov_DN -- 20141005
			
		КонецЕсли;
			
		Индексы = ШаблонИзмерений.Индексы;
		Индексы.Добавить("УпрУчет");
		Индексы.Добавить("РеглУчет");
				
		Если СтруктураКлючиАналитики <> Неопределено Тогда
			СтруктураКлючиАналитики.Вставить(ИмяСтруктурыИзмерений, ШаблонИзмерений);
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат ШаблонИзмерений;
	
КонецФункции // ШаблонИзмеренийКлючаАналитики()

Функция ПолучитьСоздатьКлючАналитики(
	СтруктураИзмерений,
	МассивИзмерений,
	ИмяСправочника,
	ИмяРегистра,
	СтруктураКлючиАналитики
	)
	
	ЭлементКлючАналитики = Неопределено;
	
	// Попробуем получить ключ аналитики из кэша.
	Если СтруктураКлючиАналитики <> Неопределено Тогда
		ЭлементКлючАналитики = ПолучитьКлючАналитикиИзТаблицы(
			СтруктураИзмерений,
			ИмяРегистра,
			СтруктураКлючиАналитики
		);
	КонецЕсли;

	Если Не ЗначениеЗаполнено(ЭлементКлючАналитики) Тогда
		
		// Возвращаем пустую ссылку на ключ аналитики затрат, если все измерения не заполнены,
		// так как такая логика (указывать пустую ссылку) предусмотрена при формировании движений
		// в общем модулей УправлениеПроизводствомДвиженияПоРегистрам
		Если ИмяРегистра = "АналитикаУчетаЗатрат" Тогда
			ЕстьЗаполненныеИзмерения = Ложь;
			Для Каждого Измерение Из СтруктураИзмерений Цикл
				ЕстьЗаполненныеИзмерения = ЕстьЗаполненныеИзмерения ИЛИ ЗначениеЗаполнено(Измерение.Значение);
			КонецЦикла;
			Если НЕ ЕстьЗаполненныеИзмерения Тогда
				Возврат Справочники[ИмяСправочника].ПустаяСсылка();
			КонецЕсли;
		КонецЕсли;
		
		// -- Begin -- Sokolov_DN -- 20141005
		// нижестоящий кусочек так же закэшируем. Посмотрим: какой прирост будет
		
		ЭлементКлючАналитики = РасширеннаяАналитикаУчетаПовторноеИспользование.ПолучитьКлючАналитики(ИмяРегистра,СтруктураИзмерений);
		
		Если ЭлементКлючАналитики = неопределено тогда	
		// --  End  -- Sokolov_DN -- 20141005
			
			// Заполним измерения регистра, т.к. после чтения они пустые.
			
			// -- Begin -- Sokolov_DN -- 20141005
			//А вот тут таки надо убранный выше менеджер сделать
			МенеджерЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи();
			ОбновитьПовторноИспользуемыеЗначения();
			// --  End  -- Sokolov_DN -- 20141005
			
			// Заполним измерения регистра, т.к. после чтения они пустые.
			ЗаполнитьЗначенияСвойств(МенеджерЗаписи, СтруктураИзмерений);
			
			// Создадим новый элемент справочника - ключ аналитики.
			СправочникОбъект = Справочники[ИмяСправочника].СоздатьЭлемент();
			СправочникОбъект.Наименование = ПолучитьПолноеНаименованиеКлючаАналитики(
				МассивИзмерений,
				МенеджерЗаписи
			);
			СправочникОбъект.Записать();
			
			ЭлементКлючАналитики = СправочникОбъект.Ссылка;
			
			МенеджерЗаписи.Ссылка = ЭлементКлючАналитики;
			МенеджерЗаписи.Записать(Ложь);
			
		КонецЕсли;
		
		// Добавим новый ключ аналитики в кэш.
		Если СтруктураКлючиАналитики <> Неопределено Тогда
			ДобавитьКлючАналитикиВТаблицу(
				СтруктураИзмерений,
				ИмяРегистра,
				ЭлементКлючАналитики,
				СтруктураКлючиАналитики
			);
		КонецЕсли;
		
	КонецЕсли;
	
	Если ЭлементКлючАналитики = Неопределено Тогда
		ЭлементКлючАналитики = Справочники[ИмяСправочника].ПустаяСсылка();
	КонецЕсли;
	
	Возврат ЭлементКлючАналитики;
	
КонецФункции // ПолучитьСоздатьКлючАналитики()
 

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Николай Терновой (ojiojiowka) 07.10.14 08:52
К сожалению, УПП нет под рукой, поэтому задам пару вопросов. Вторая часть статьи годная, единственное, могут возникнуть проблемы, если в этот момент меняются данные (хоть это и редко случается). Я бы запихнул это в параметры сеанса и обновлял бы их при изменении. По первой части:
1) Разве эффект не был бы таким же, если у физического лица включить индексирование? Меня просто не очень прельщает кардинальная переделка порядка измерений. Здесь помогло, в другом случае может навредить. Надо полностью оценить все основные операции над этим регистром.
2) Не будет ли являться избыточным для первого измерения (физического лица) ещё и установка свойства индексировать? Почитайте про структуру индексов 1С. Нужный индекс уже будет, зачем создавать избыточный с периодом между физ лицом и остальными измерениями?
alexscamp; DNSokol; +2 Ответить 1
2. Дмитрий Соколов (DNSokol) 07.10.14 11:29
(1) ojiojiowka,

Отвечу по порядку:

Про изменение данных. Да, данные меняются, но, не просто так по коду ползал. Функция ЗаполненыНастройкиАналитикиУчета() делает выборку практически из статичного справочника, которые меняется не чаще чем почти никогда. Это же касается и функции ШаблонИзмеренийКлючаАналитики(). Самый большой вопрос был по функции ПолучитьКлючАналитики(). Тут возможны изменения, в т.ч. и при расчете себестоимости. Поэтому, если вызов данной функции вернул пустой результат, отрабатывает уже типовое создание ключа аналитики, после чего вызывается стандартная функция ОбновитьПовторноИспользуемыеЗначения(). Единственное, чем плох этот алгоритм, так это тем, что ОбновитьПовторноИспользуемыеЗначения() сбрасывает кэш не конкретной функции, для которой включено повторное использование значений, а весь кэш. Тем не менее, т.к. вызовы сброса сильно не частые (у меня в расчете себестоимости сбрасывается кэш 3-4 раза, то использование повторно возвращаемых значений дает очень положительный эффект на быстродействие.

Про эффект. Нет, не был бы. Подробно вспоминать (ибо уже давно не кодер) как работают механизмы 1С просто времени не было. К сожалению. Просто есть факт того, что если измерение сделать первым по списку, то получил прирост скорости работы. Если к этому включить индексирование (в конфигураторе), то прирост будет еще более существенный. Если просто включить индексирование, то прирост будет не такой, как с перемещением измерений.

Про "Надо полностью оценить все основные операции". Это не просто сделать надо, это обязательно надо сделать и в первую же очередь. Я про это в статье и написал. Т.к. если просто переместить измерения и включить индексирование, то можно получить ни прирост в скорости работы, а ухудшение. Например, если в УПП включено использование заказов, и, информации по заказам сильно больше в регистре, чем информации по переданным материалам, то мои изменения приведут к не желательным последствиям.

Про избыточность индекса. Нет, не будет избыточным. Просто похоже 1С при создании на SQL таблицы для регистра сведений (по крайней мере для независимого) делает кластерный индекс вида "измерение1+измерение2+измерение3", а если на измерение повесить галку "индексировать", то будет сделан дополнительно еще один индекс по тем полям, для которых галки "индексировать" установлены. Именно по этой причине злоупотреблять галочками "индексировать" нельзя, т.к. если, например, измерений будет более чем много, то хаотичная расстановка галочек приведет к тормозам при записи (много индексов будет) и отсутствию прироста скорости при чтении (всё равно запросы не будут попадать в индексы и будут сканы таблиц на SQL).

В общем и целом как-то так.
DrBlack; Makushimo; unoDosTres; +3 Ответить 2
3. Алексей 1 (AlX0id) 07.10.14 13:14
(2) DNSokol,
Про избыточность индекса. Нет, не будет избыточным. Просто похоже 1С при создании на SQL таблицы для регистра сведений (по крайней мере для независимого) делает кластерный индекс вида "измерение1+измерение2+измерение3", а если на измерение повесить галку "индексировать", то будет сделан дополнительно еще один индекс по тем полям, для которых галки "индексировать" установлены.

Ну и в чем тогда дополнительная польза от индекса "Измерение1" при наличии индекса "измерение1+измерение2+измерение3"?
4. Дмитрий Соколов (DNSokol) 07.10.14 14:08
(3) AlX0id,

Выгода в скорости. Если у меня запрос только по ФЛ, то SQL выберет индекс по ФЛ, который более оптимален, чем кластерный индекс => запрос отработает быстрее.
5. Павел Алексеенко (qwinter) 07.10.14 14:18
(2) DNSokol, вы заблуждаетесь, 1С не создает индексов по типу: "измерение1+измерение2+измерение3" регистры сведений индексируются по умолчанию только по регистратору.
6. Павел Алексеенко (qwinter) 07.10.14 14:26
(3) AlX0id, для данного регистра разницы между между просто врубить индексирования, и переместить и врубить в быстродействии не будет.

А вообще выборка по первому индексу всегда эффективней, чем по второму, третьему и т.д. Поэтому перемещение относительно других индексированных элементов действительно дает эффект. Но так как данный регистр не подчинен регистратору и не имеет реквизитов с свойством "Индексировать" то у него нет таблиц индексов. И поставив "Индексировать" у физического лица вы создадите единственный индекс. И не важно, какой будет порядок у реквизитов.
7. Алексей 1 (AlX0id) 07.10.14 14:48
(5) qwinter,
Непериодический регистр сведений
Индекс
Условие и описание
Измерение1 + [Измерение2 +...]
Есть хоть одно измерение регистра.
Индекс, включающий все измерения в том порядке, в котором они заданы при конфигурировании.

ИзмерениеN + Измерение1 + [Измерение2 +...]
Измерению "ИзмерениеN" задано свойство "Индексировать" или свойство "Ведущее" и при этом это не первое и не единственное измерение.
Индекс, включающий все измерения. Первое поле - ИзмерениеN, затем все остальные измерения в том порядке, в котором они заданы при конфигурировании.



В частности:
Таблица: РегистрСведений.АналитикаУчетаПартий, Имя таблицы хранения: InfoRg19844, Назначение: Основная
- поля:
СтатусПартии (Fld19845)
Заказ (Fld19846)
ДоговорКомитента (Fld19847)
Комиссионер (Fld19848)
ДоговорКомиссионера (Fld19849)
ДокументПередачи (Fld19850)
ФизЛицо (Fld19851)
НазначениеИспользования (Fld19852)
Ссылка (Fld19853)
(SimpleKey)
- индексы:
ByDims
СтатусПартии + Заказ + ДоговорКомитента + Комиссионер + ДоговорКомиссионера + ДокументПередачи + ФизЛицо + НазначениеИспользования (Fld19845 + Fld19846 + Fld19847 + Fld19848 + Fld19849 + Fld19850 + Fld19851 + Fld19852)
ByResource19854
Ссылка + СтатусПартии + Заказ + ДоговорКомитента + Комиссионер + ДоговорКомиссионера + ДокументПередачи + ФизЛицо + НазначениеИспользования (Fld19853 + Fld19845 + Fld19846 + Fld19847 + Fld19848 + Fld19849 + Fld19850 + Fld19851 + Fld19852)
BySimpleKey
SimpleKey (SimpleKey)
alexscamp; qwinter; jan27; +3 Ответить
8. Алексей 1 (AlX0id) 07.10.14 14:52
(4) DNSokol,
В чем заключается его оптимальность по отношению к кластерному индексу можете сказать?

ЗЫ. А по поводу ЗаполненыНастройкиАналитикиУчета() - запустил у себя расчет себестоимости - вызывается ровно 8 раз.. Видимо, сильно зависит от настроек учета..
9. John Smith (PiccaHut001) 07.10.14 15:19
Автор, спасибо. Ускорили РАУЗ в 30!!! раз. Видно, писателям типовой УПП было недосуг заморачиваться просмотром своего овнокода шедеврального творения. Работает на 10 документах, и ладно. А потом эти удакисертифицированные преподаватели запрещают нам писать запросы в цикле(даже если цикл из 2 итераций).
BorovikSV; DrBlack; +2 Ответить
10. Дмитрий Соколов (DNSokol) 07.10.14 15:29
(5) qwinter,

Создает, но немного не так, как я описал. Тут ошибочка. Когда смотрел на SQL базу, то посмотрел на регистр, в котором несколько измерений индексировалось.
11. Дмитрий Соколов (DNSokol) 07.10.14 15:32
(6) qwinter,

Ну, тут нет времени подробно разбираться. Тут просто констатирую факт, что разница есть, и, она видна. Если просто порядок измерений поменять, то выборка быстрее производится. Если включить индексирование, то создается на SQL еще один индекс (к тому, что уже имеется "по умолчанию"). Так что порядок имеет значение.
12. Дмитрий Соколов (DNSokol) 07.10.14 15:37
(8) AlX0id,
это уже в книжки по СУБД. Сорри.
13. Алексей 1 (AlX0id) 07.10.14 15:52
(12) DNSokol,
Ну и на том, спасибо, что отправили )) Если на пальцах, то:
Кластерный индекс - это сама таблица. А вот некластерный индекс в вашем случае - это только ключ из одного столбца.
Если в таблице несколько столбцов, а в некластерном индексе ключ из одного, то и занимать таблица будет больше страниц, чем некластерный индекс, соответственно, чтобы просканировать некластерный индекс надо меньше прочитать экстентов серверу. Отсюда и выигрыш.

14. uno dos (unoDosTres) 07.10.14 16:17
ну идея понятна, вот только функцию
ПолучитьКлючАналитики
найти не удалось, я так понимаю все три перечисленные функции вызывались из ОбщегоМодуля "РасширеннаяАналитикаУчета", правда Релиз конфы посвежей, думаю попробовать хотя бы на вызове двух функций проверить с изменением порядка измерений в регистре АналитикаУчетаПартий
15. Александр Капустин (kapustinag) 07.10.14 16:25
(8) AlX0id, Оптимальность/Неоптимальность индекса по одному измерению по сравнению с кластерным индексом - вещь относительная, то есть в разных условиях эксплуатации БД и при разных характеристиках таблицы преимущество может быть то у одного индекса, то у другого.
С одной стороны, кластерный индекс физически в файле базы данных размещается таким образом, чтобы получить выигрыш при чтении данных - то есть узлы кластерного индекса располагаются рядом со строками самой таблицы. Это - в плюс кластерному индексу.
С другой стороны, индекс по одному измерению может занимать существенно меньше места, то есть может быть прочитан за очень малое количество операций физического чтения. Это - в плюс индексу по одному измерению.
Но - еще раз повторюсь - эти плюсы и минусы могут пересиливать друг друга на разных запросах, разной наполненности таблиц, разной степени фрагментированности БД, разной разбивке БД на файлы...
16. Дмитрий Соколов (DNSokol) 07.10.14 16:44
(14) unoDosTres,

Описался немного. Функция называется "ПолучитьСоздатьКлючАналитики". Сейчас текст подправлю. Соответственно в Расширенной аналитике учета измененный кусок кода вот так выглядит:

		Если ИмяРегистра = "АналитикаУчетаЗатрат" Тогда
			ЕстьЗаполненныеИзмерения = Ложь;
			Для Каждого Измерение Из СтруктураИзмерений Цикл
				ЕстьЗаполненныеИзмерения = ЕстьЗаполненныеИзмерения ИЛИ ЗначениеЗаполнено(Измерение.Значение);
			КонецЦикла;
			Если НЕ ЕстьЗаполненныеИзмерения Тогда
				Возврат Справочники[ИмяСправочника].ПустаяСсылка();
			КонецЕсли;
		КонецЕсли;
		
		// -- Begin -- Sokolov_DN -- 20141005
		// нижестоящий кусочек так же закэшируем. Посмотрим: какой прирост будет
		
		//МенеджерЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи();
		//ЗаполнитьЗначенияСвойств(МенеджерЗаписи, СтруктураИзмерений);
		//
		//МенеджерЗаписи.Прочитать();
		//
		//Если МенеджерЗаписи.Выбран() Тогда
		//	ЭлементКлючАналитики = МенеджерЗаписи.Ссылка;
		//Иначе
		ЭлементКлючАналитики = РасширеннаяАналитикаУчетаПовторноеИспользование.ПолучитьКлючАналитики(ИмяРегистра,СтруктураИзмерений);
		// --  End  -- Sokolov_DN -- 20141005
		
		Если ЭлементКлючАналитики = неопределено тогда	
			// Заполним измерения регистра, т.к. после чтения они пустые.
			
			// -- Begin -- Sokolov_DN -- 20141005
			//А вот тут таки надо убранный выше менеджер сделать
			МенеджерЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи();
			ОбновитьПовторноИспользуемыеЗначения();
			// --  End  -- Sokolov_DN -- 20141005
			
			ЗаполнитьЗначенияСвойств(МенеджерЗаписи, СтруктураИзмерений);
			
			// Создадим новый элемент справочника - ключ аналитики.
			СправочникОбъект = Справочники[ИмяСправочника].СоздатьЭлемент();
			СправочникОбъект.Наименование = ПолучитьПолноеНаименованиеКлючаАналитики(
				МассивИзмерений,
				МенеджерЗаписи
			);
			СправочникОбъект.Записать();
			
			ЭлементКлючАналитики = СправочникОбъект.Ссылка;
			
			МенеджерЗаписи.Ссылка = ЭлементКлючАналитики;
			МенеджерЗаписи.Записать(Ложь);
			
		КонецЕсли;
		
		// Добавим новый ключ аналитики в кэш.
		Если СтруктураКлючиАналитики <> Неопределено Тогда
			ДобавитьКлючАналитикиВТаблицу(
				СтруктураИзмерений,
				ИмяРегистра,
				ЭлементКлючАналитики,
				СтруктураКлючиАналитики
			);
		КонецЕсли;
		
	КонецЕсли;

...Показать Скрыть


а в свой модуль с повторным использованием надо добавить вот такую функцию:
Функция ПолучитьКлючАналитики (ИмяРегистра, СтруктураИзмерений) экспорт
	
	МенеджерЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи();
	ЗаполнитьЗначенияСвойств(МенеджерЗаписи, СтруктураИзмерений);
	
	МенеджерЗаписи.Прочитать();
	
	Если МенеджерЗаписи.Выбран() Тогда
		Возврат МенеджерЗаписи.Ссылка;
	Иначе
		Возврат неопределено;
	конецЕсли;
	
КонецФункции

...Показать Скрыть
17. Дмитрий Соколов (DNSokol) 07.10.14 16:51
(15) kapustinag,

именно так! Помимо этого есть еще множество нюансов, влияющих на конечный результат. Просто в первой части статьи хотел показать сам принцип, что прежде чем лезть в SQL и что-то там докручивать, можно внести небольшие изменения в порядок следования измерений и индексирование. Если делать всё вдумчиво, а не просто "индексы ускоряют, значит сейчас везде понатыкаю галок <индексировать>" то можно получить достаточно существенный прирост производительности.
18. Константин Соболевский (Константин С.) 07.10.14 18:29
тогда уж опиши эту процедуру)
"ШаблонИзмеренийКлючаАналитики"

19. Дмитрий Соколов (DNSokol) 07.10.14 18:39
(18) Константин С.,

)))) Да я хотел измененные модули приложить, а они только при включенных "поборах" прикладываются :) Изменил статью. В коней статьи добавил код, который менялся.
20. Алексей 1 (AlX0id) 07.10.14 22:56
(15) kapustinag,
Ну вот поэтому-то я и задал вопрос автору, почему он в данном случае считает более оптимальным именно некластерный индекс.

Но чем больше я в это вдаюсь, тем все "страньше и страньше".
Во-первых, некластерный индекс, создаваемый 1С, не так уж и сильно отличается по длине от кластерного в случае того же регистра АналитикаУчетаПартий - так как включает в себя все измерения регистра. То есть, короче ровно на один ресурс.
Во-вторых, по результатам замера производительности расчет себестоимости делает в основном не запросы по Физлицу, как можно предположить из статьи (но довольно странно с точки зрения логики РАУЗ), а по ресурсам регистров аналитики (которые как раз-таки индексированы в типовой).

Вот со второй частью повествования я могу согласиться, хотя у меня данная ситуация и не повторяется. А вот с первой - что-то слишком натянуто. Непонятно, откуда взята мысль, что надо индексировать именно это измерение.

ЗЫ. Начал ковыряться в структуре индексов - вообще наткнулся на такую картину:
Регистр аналитики до реструктуризации
И такие индексы по всем регистрам сведений. То есть НЕкластерные.
А вот если изменить структуру регистра в 1С - тут же появляется кластерный индекс..
ojiojiowka; +1 Ответить 1
21. Дмитрий Соколов (DNSokol) 07.10.14 23:23
(20) AlX0id,

Как бы это по мягше то сказать то.... В общем, я писал уже, что не плохо бы книжки почитать.

Например, про кластерные индексы можно тут узнать. Там же можно узнать почему кластерный индекс на таблицу может быть только один, а не много. И изучив то, как MS SQL строит кластерный индекс можно понять, почему порядок измерений влияет на скорость выборок, при том, существенно.

Про физлицо. Узнать почему нужно индексировать в моем случае именно это измерение - можно из статьи. Там явно это написано. Там же написано, что нужно сделать перед тем, как принять решение о том, что физлицо нужно переместить "вверх" списка измерений.

В остальном вам помогут или ЖКК или изучение того, как РАУЗ работает, а конкретно, как строятся выборки по аналитикам и почему в конкретно моем примере перемещение физлица дало прирост в скорости.

Приношу извинения, но просто заниматься преподаванием основ СУБД нет времени.
22. Антон Стеклов (asved.ru) 08.10.14 07:41
Что касается дополнительного индекса по первому полю кластерного индекса - очень странна Ваша мысль. Регистр-то непериодический, независимый, поэтому поле действительно идет первым в кластерном индексе.

Размер дополнительного индекса возможно, будет немного меньше (а возможно - и нет, тут смотреть надо, не задублировалось ли в нем первое поле), но потом все равно придется делать key_lookup, так что далеко не факт, что СУБД выберет именно такой путь. Это возможно при высочайшей селективности, отсутствии требуемых страниц в буфере и нагруженности I/O.

Если бы Вы не ограничивались описанием работы исключительно на уровне 1С, а привели план запроса, а заодно и latches по нему для случаев с дополнительным индексом и без него, ваши мысли были бы яснее.

В общих чертах можно сказать, что порядок измерений регистра сведений действительно влияет только на эффективность исполнения запроса по нему. Так что подход с изменением структуры верен при условии, что нет других существенных обращений, которым изменение этого порядка помешает. Есть еще возможность создания специализированного индекса средствами СУБД, хоть это и есть нарушение лицензионного соглашения, и официально я рекомендовать такое не могу.

Хотелось бы, конечно, чтобы платформа позволяла построение произвольных индексов.
alexscamp; qwinter; jan27; ojiojiowka; AlX0id; +5 Ответить 1
23. Алексей 1 (AlX0id) 08.10.14 10:15
(21) DNSokol,
А где вы увидели в моем сообщении, что я ищу несколько кластерных индексов по таблице? В картинке в явном виде показано, что до реструктуризации нет КЛАСТЕРНОГО индекса в принципе, а после, как сказано в сообщении - есть.

Если бы Вы не ограничивались описанием работы исключительно на уровне 1С, а привели план запроса, а заодно и latches по нему для случаев с дополнительным индексом и без него, ваши мысли были бы яснее.

Вот чего я ожидал увидеть в статье, а не некое эмпирически подобранное решение.

В остальном вам помогут или ЖКК или изучение того, как РАУЗ работает, а конкретно, как строятся выборки по аналитикам и почему в конкретно моем примере перемещение физлица дало прирост в скорости.

Ну так приведите же хоть один запрос из расчета себестоимости, где этот индекс дает прирост производительности, и половина вопросов отпадет.
24. Дмитрий Соколов (DNSokol) 08.10.14 10:49
(22) asved.ru,

Я же в преамбуле к статье написал, что тут приведена рекомендация по тому, как можно повысить производительность. И там же написал, что некоторые вещи просто принимаются на веру. У меня при написании материала не было задачи доказать, что то, что принято за аксиому, аксиомой и является. Более того, у меня так же не было задачи блестать знаниями профайлера и кому-то что-либо доказывать.

Еще раз - основная задача материала - дать небольшую базу о том, используя какие основы и какие подходы можно существенно поднять производительность, а не загрузить читателя потоком сознания. И судя по комментариям, некоторым статься помогла. Т.е. цель материала достигнута.

Именно поэтому, все описание ограничено средствами 1С и тем, как средствами 1С модно улучшить работу. И именно поэтому тут нет дополнительной "технической доказательной базы". Если есть пытливые умы, которые хотят посидеть под профайлером и почитать книжки - я не против и ни в коей мере не ограничиваю. Берите профайлер и вперед. Можете свою статью написать, где будет большая доказательная база с планами выполнения запросов и т.д.

Сейчас имеем следующее - цель статьи достигнута. На этом большая и жирная точка. Если у меня будет другая цель, напишу по другому.
iterf@yandex.ru; +1 Ответить 1
25. Дмитрий Соколов (DNSokol) 08.10.14 10:54
(23) AlX0id,
в школу. Учится. Цели проводить обучение у меня не стоит. Ровно как и не стоит цели рассказывать основы СУБД. Про планы запроса - читаем очень внимательно и вдумчиво преамбулу к статье. Там кратко описано содержание статьи. Нужен профайлер и полный технический анализ - берите в руки инструменты и вперед. Напишите тут свой доклад на тему улучшения производительности с техническим обоснованием. У меня задачи загрузить потоком сознания и показать какой я крутой СУБДист - не было.
26. Алексей 1 (AlX0id) 08.10.14 11:11
(25) DNSokol,
Мдэ? То-то я смотрю, вы, как "крутой СУБДист" меня в школу "учится" отправляете ))
Хорошо, не буду задавать вам вопросов, которые вам неудобны.
ilov_boris; +1 Ответить
27. AlexBar (AlexBar) 08.10.14 11:37
Мне не совсем понятно в чем выигрыш при получении шаблона через новый модуль? При входе в функцию "ШаблонИзмеренийКлючаАналитики" передается параметр "СтруктураКлючиАналитики" которая и содержит "кешированные" шаблоны. Запрос к СУБД производится только в том случае, если в этой структуре шаблон не найден. Смотрите строку
Если СтруктураКлючиАналитики = Неопределено
     ИЛИ Не СтруктураКлючиАналитики.Свойство(ИмяСтруктурыИзмерений, ШаблонИзмерений) Тогда


Т.е. к СУБД обращение производится только один раз для каждого из регистров "УчетЗатрат" ("УчетЗатратРегл"). Вы анализировали сколько раз при вызове данной функции выполняется запрос?

То же самое касается и "ПолучитьСоздатьКлючАналитики". Для каждого ключа аналитики действие производится только один раз, после получения ключа он помещается в таблицу и в следующий раз считывается уже оттуда:

    // Попробуем получить ключ аналитики из кэша.
    Если СтруктураКлючиАналитики <> Неопределено Тогда
        ЭлементКлючАналитики = ПолучитьКлючАналитикиИзТаблицы(
            СтруктураИзмерений,
            ИмяРегистра,
            СтруктураКлючиАналитики
        );
    КонецЕсли;

    Если Не ЗначениеЗаполнено(ЭлементКлючАналитики) Тогда
...Показать Скрыть


Т.е. обращение к СУБД и запись в СУБД ключа производится производится только один раз для каждого набора аналитики.
Вы анализировали эту ситуацию прежде чем оптимизировать данные участки кода?
28. Дмитрий Соколов (DNSokol) 08.10.14 13:39
(27) AlexBar,

Я тоже сначала так думал. Но, расстроило меня то, что СУБД даки постоянно читалась. Поэтому, выигрыш в том, что мы не лезем каждый раз в базу.

Так вот, если уж разбираться подробно, то если смотреть вызовы функции ШаблонИзмеренийКлючаАналитики в модуле расширенной аналитики, то видно приблизительно следующее:

		Запрос.Текст = "ВЫБРАТЬ";
		СтруктураИзмерений = Новый Структура();
		МассивИзмерений = Новый Массив();
		ШаблонИзмерений = ШаблонИзмеренийКлючаАналитики(КлючАналитики.Ключ, Неопределено);

...Показать Скрыть


т.е. вместо "кэша" всегда и во всех вызовах передается "неопределено". Итого у нас получается 2 варианта: использовать повторное использование значений или городить огород с реализацией кэша. Я выбрал второй вариант, т.к. изменения типовых модулей минимальны, а это значит, что обновлять их будет проще, в случае надобности. Собственно, это еще и ответ на вопрос про анализ :) естественно анализировал, и, естественно смотрел что в функцию передаётся.

И да, то же самое касается и "ПолучитьСоздатьКлючАналитики". Эта функция вызывается в единственном месте в функции "ПолучитьЗначениеКлючаАналитики". В данную функцию передается тот самый "кэш" последним параметром, и... и он во всех вызовах использует или "неопределено" или туда передается пустая структура, как, например в процедуре "ПолучитьАналитикуРаспределенияЗатратНаВыпуск", которая вызывается из "ВыполнитьРаспределениеСтрокиРасходовНаВыпуск" которая вызывается из "ВыполнитьРаспределениеРасходов" в которой вот это перед вызовом:
СтруктураКлючиАналитики = Новый Структура


поэтому в этом "кэше" всегда пусто. Поэтому чтение СУБД происходит при каждом новом вызове. Можно было всё эту вереницу вызовов размотать, докопаться до того, как заставить всё это работать с кэшем, а можно было просто сделать повторное использование.

У меня есть предположения, почему кэш перестали использовать, но, это только предположения.
29. AlexBar (AlexBar) 08.10.14 15:41
Вероятно мы с Вами смотрим разные куски кода указанного модуля.
Приведенный Вами код имеет отношение только к процедурам тестирования и проверки ключей аналитики: "ОбновитьНаименованияКлючейАналитики" и "ПроверитьСсылочнуюЦелостностьКлючейАналитики". Пожалуй это мы обсуждать не будем, так как к нашей теме отношения не имеет.
В функции же, которая возвращает значение ключа аналитики ("ПолучитьЗначениеКлючаАналитики") используется иной код:
	ШаблонИзмерений = ШаблонИзмеренийКлючаАналитики(
		ИмяРегистра,
		СтруктураКлючиАналитики
	);

Именно эта функция и используется во всех механизмах расчетов и формирования движений РАУЗ.

При анализе видно что при начале формирования движений, не обязательно РСВ, СтруктураКлючиАналитики создается пустой, но по мере формирования движений структура наполняется шаблонами.
30. Дмитрий Соколов (DNSokol) 08.10.14 17:03
(29) AlexBar,

Сначала вернусь к первоначальному вопросу "в чем выигрыш" - выигрыш во времени исполнения функции получения данных. При идентичном наборе входящих параметров функция возвращает результат без исполнения. Конкретно не производится выборка базы. Во времени этот выигрыш конкретно по указанной процедуре - 40 минут расчета себестоимости. Это мной задокументированный факт. С часами, думаю, спорить бесполезно и бессмысленно как минимум по одной причине - время выполнения - это объективная констатация факта.

Далее, нет, тут вы не правы (про тестирование). В процедуру "ШаблонИзмеренийКлючаАналитики" неопределено засовывается именно в процедурах расчета, а не в процедурах тестирования. Данная функция вызывается из процедур "ПолучитьЗначениеКлючаАналитики", "ОбновитьНаименованияКлючейАналитики" и "ПроверитьСсылочнуюЦелостностьКлючейАналитики". в 2 и 3 в качестве "кэша" засовывается "неопределено". в процедуре 1 - передается структура. Сам вызов при расчете себестоимости поисходит из модулей УправлениеПроизводствомДвиженияПоРегистрам и "процедурыРасчетаСебестоимостиРасширеннаяАналитика". Где в каждом месте вызова "основной процедуры" стоит что-то вида:
Процедура СформироватьДвиженияПоВыпускуУслуг(СтруктураШапкиДокумента)
	
	СтруктураНаборыЗаписей  = РасширеннаяАналитикаУчета.ПолучитьНаборыЗаписейРегистров(СтруктураШапкиДокумента);
	СтруктураКлючиАналитики = Новый Структура;
	
// ля-ля-ля

	Если НЕ Результат.Пустой() Тогда
		
		Выборка = Результат.Выбрать();
		
		Пока Выборка.Следующий() Цикл
			
	
...Показать Скрыть


в цикле происходит вызов функции ПолучитьЗначениеКлючаАналитики. Как только процедура СформироватьДвиженияПоВыпускуУслуг завершается, про кэш можно забыть. его не будет. Ибо при следующем вызове данной процедуры мы получим опять вот это:

	СтруктураКлючиАналитики = Новый Структура;


Вызовов "основных процедур", где сбрасывается кэш более чем много. Не знаю как сюда картинку прилепить, но вызов вынесенного запроса производится более 300 тысяч раз. в типовом варианте это 300 тысяч обращений к СУБД. В то же время, выборка максимум вернет 30 тыс. вариантов записей. оставшиеся разы - это именно сбрасывания кэша. На этом и основан эффект, потому как при повторном использовании нам всё равно на эти обнуления. Если входящие в вызов значения идентичны закэшированным - вернется кэш.

Более того, я знаю даже почем этот "кэш" обнуляется. Все происходит потому, что этот "кэш" нужен исключительно для конкретного этапа расчета по конкретному виду расчета. В этом "кэше" должны содержаться записи, необходимые только для данного этапа, а не вообще все записи. В то же время, повторное использование значений наполнит этот "кэш" только нужными записями. Всё остальное - в памяти сервера.

С остальными процедурами картина идентична. Описывать их не буду, т.к. это и так выходит за рамки того, что в статье хотел показать.
31. Антон Стеклов (asved.ru) 08.10.14 17:04
(24) DNSokol, т.е. Вы вводите людей в заблуждение на предмет дополнительной индексации первого поля кластерного индекса - и считаете, что цель статьи достигнута?
ojiojiowka; +1 Ответить 1
32. Дмитрий Соколов (DNSokol) 08.10.14 17:20
(31) asved.ru,
Напишите свою статью. без "заблуждений". Это первое. Второе - я не буду объяснять почему индекс по ФЛ будет работать быстрее чем имеющийся кластерный индекс. У меня не стоит цели рассказывать основы MSSQL. И третье - зачастую людям нужно получить эффект, а не пространственные объяснения. Я в преамбуле написал, что для объяснений есть книги. Я не знаю как по другому еще сказать. Перечитайте что ли еще раз то, что жирным выделил.

Ну и да, четвертое - постройте табличку с 5 полями и кластерным индексом. Сделайте выборку с условием сначала по первому полю, потом по 4. Измерьте скорость выполнения. Изучите план выполнения. Потом на эту же табличку постройте индекс на первое поле, так же сделайте выборку по индексу из первого поля. Скорость измерить так же надобно. А вот потом на основе полученного эксперимента можете написать здесь статью про то, какой нехороший я, вводящий людей в заблуждение, и какой хороший вы. Заодно посмотрим, на сколько эта статья будет популярна и скольким людям ваша статья поможет увеличить скорость расчета себестоимости в 10 и более раз.

Тема закрыта.
33. Евгений Сосна (pumbaE) 08.10.14 17:40
34. Николай Терновой (ojiojiowka) 08.10.14 18:04
(32) по поводу свойства "индексировать" у поля "ФизическоеЛицо" Вы так и не ответили. После изменения порядка измерений оно так и осталось избыточным...
35. AlexBar (AlexBar) 08.10.14 18:08
Дмитрий, относитесь ко всему спокойнее. Вы же видите по комментариям что есть люди которым Ваша статья помогла, а это по моему мнению очень важно! А сколько еще людей прочтет вашу статью и будут Вам благодарны!
Я, да и другие коллеги, не пытаюсь Вас критиковать, всего лишь пытаюсь понять суть.
Вот допустим Вы приводите данные что вызов функции "ЗаполненыНастройкиАналитикиУчета" производится более 300 тысяч раз за время проведения одного документа РСВ. Соответственно столько же раз выполняется запрос. В такой ситуации вполне логичное решение от этого избавиться, так как это само по себе не нормально.
Я запустил замеры времени на своей базе на момент расчета себестоимости. После расчета посмотрел результат: у меня вызов этой функции производится всего 2 раза. При этом аналитики учета у нас доработаны, в ключи введены еще пара измерений. Расчет себестоимости не превышает 10 минут.
Вроде 10 минут и так не много, однако если есть не оптимальные участки кода, то их бы в любом случае хотелось бы ликвидировать. Вот и копаюсь вместе с Вами в данных процедурах, чтобы понять каким образом получился выигрыш.
36. Дмитрий Соколов (DNSokol) 08.10.14 18:19
(35) AlexBar,
Сорри, просто 1001 дело когда делаешь, заносит иногда. По теме - отвечу позже. У нас в базе объективно много таких вызовов. Распишу всё ближе к ночи.
37. Антон Стеклов (asved.ru) 08.10.14 19:55
(32) DNSokol,
Второе - я не буду объяснять почему индекс по ФЛ будет работать быстрее чем имеющийся кластерный индекс


Зато я уже объяснил несколькими комментариями выше, почему он НЕ будет работать быстрее.

Я в преамбуле написал, что для объяснений есть книги

Покажите мне, пожалуйста, книгу, в которой говорится, что SQL для выборки по первому полю кластерного индекса будет использовать полный некластерный индекс с этим же полем на первом месте.

И самое смешное то, что от установки флажка "индексировать" на первом измерении независимого непериодического регистра сведений структура индексов не меняется вообще.

alexscamp; Ovrfox; EliasShy; ojiojiowka; +4 Ответить 1
38. Дмитрий Соколов (DNSokol) 08.10.14 23:08
(35) AlexBar,

про 300 тыс. К сожалению, от этого не избавиться. Точнее, можно избавиться только одним способом - избавившись от РАУЗа как такового. Дело в том, что в самом регистре с аналитиками около 30 тыс. ключей. Это значит ровно одно - будет минимум 30 тыс. обращений минимум. Распределение затрат многоэтапное. Я уже неоднократно проползал весь РАУЗ. Там или глобально все переделывать надо, а это трудозатраты бешенные, или пытаться минимизировать количество обращений к СУБД. Я в общем и целом специально акцент сделал на физлицах и материалах. Если в организации большое количество рабочего персонала и большое количество подразделений, то в аналитикеУчетаПартий сформируется столько уникальных записей, сколько возможно вариантов ФизЛицо+ДокументПередачи+НазначениеИспользования. Т.о. выходит что количество таких комбинаций безгранично. В моем случае пока это 30 тыс. вариантов. РАУЗ пока из все не вычитает, бузет лезть в базу. Далее, 4 этапа распределения этих затрат, но, есть "перезакрытия". Всё это приводит к тому, что типовыми механизмами вычитываться все эти 30 тыс. позиций будут около 10 раз (точнее, количество итераций больше, но, не все 30 тыс. ключей за раз вычитываются).

В итоге, что мы имеем? А имеем то, что при таком объеме спецодежды и спецоснастки (а такой объем комбинаций именно по этой части учета) нужно или упрощать учет (не реально), или оптимизировать чтения базы. Последний вариант наименее трудозатратный в сило возможности использования повторного использования возвращаемых значений. В этом случае вся эта куча аналитит будет прочитана только один раз за расчет себестоимости.
39. Дмитрий Соколов (DNSokol) 08.10.14 23:39
(37) asved.ru,

ну-ну. С выключенной галкой "индексировать" время расчета себестоимости 11:20. Если включаем эту галочку и проводим расчет себестоимости, то время получается 8:02.

Внимание вопрос - что делает галочка?
40. AlexBar (AlexBar) 09.10.14 00:22
(38) DNSokol,
Каким методом ты подсчитывал количество вызовов функции "ЗаполненыНастройкиАналитикиУчета"?
Мне сейчас интересен не столько механизм оптимизации, сколько понять причину таких многочисленных вызовов.
Расчет себестоимости оперирует только ключами аналитики в процессе решения уравнений.
Даже при расчете базы распределения ключи не создаются, а считываются из базы на основании настроек регистра способов распределений.
Чтение и создание ключей аналитики производится только при формировании документов регистрации хозяйственной деятельности, но никак не РСВ. Этот документ не создает ключи аналитики, следовательно ему незачем столько раз читать шаблоны.
Дима, у тебя точно типовой код РСВ?
Попробуй провести РСВ в 3 итерации: первый документ выполняет пункты 1-2, второй 3-4, третий 5.
Зафиксируй сколько времени у тебя займет проведение каждого из этих документов.
Зафиксируй при какой итерации происходит многочисленный вызов обозначенной функции.
Не психуй и не поленись. Очень хочется разобраться.

ojiojiowka; AlX0id; +2 Ответить 2
41. Владимир Родионов (Балабас) 09.10.14 09:05
(40) количество вызовов определяется с помощью замера производительности.
42. Дмитрий Соколов (DNSokol) 09.10.14 10:43
(40) AlexBar,
Расчет типовой. РСВ естественно не создает. Я специально написал про материалы и физлиц. Типовой документ "Передача материалов в эксплуатацию" создает ключи. у меня таких документов в месяц более 200. В каждом документе около 100 строчек. Помимо этого, есть еще возвраты, перемещения и т.д. Которые так же ключики создают. В идеале, если ключ единожды создан, то он должен использоваться, если бы не одно "но". В типовой УПП есть механизм назначений использования спецодежды и спецоснастки. В этом механизме используется справочник "назначения использования", который в свою очередь подчинен номенклатуре. Т.е. для каждой номенклатурной позиции будет столько записей в этом справочнике, сколько вариаций "счет учета/статья/подразделение/метод списания". У меня при 50 подразделениях, 10 статьях затрат (5 статей Принимаемые + 5 статей не принимаемые) и 4 счетах учета, используемых для отражения амортизации спец. одежды, на каждую позицию создается в итоге (т.в. спец* выдается во все подразделения) около 500-800 записей в этот справочник. А это всё - уникальные ключи для РАУЗа. Вот отсюда и вызовы.

Я, собственно, по этому и писал, что такое ускорение, как в статье, в первую очередь касается тех, у кого большой объем спец* на производстве. Можно, конечно, переделать этот блок, но, опять же, это упирается в большое количество трудозатрат. Проще провести оптимизацию вызовов. По крайней мере, на данном этапе.

Что до эксперимента, то каждый документ "Передача материалов в эксплуатацию" в итоге или создает, или использует 100 ключей. которые еще и "длинные", потому как для того, что бы по спец. одежде добраться до затратного счета, нужно проделать путь "Документ передачи (в измерениях для РАУЗ есть) -> Физлицо (в измерениях для РАУЗ) -> Назначение использования (ключ) -> Способ отражения расходов (по ссылке из ключа)".

Про измерения. После того как попередвигал измерения, документ стал проводиться около 3х секунд. До этого около минуты проводился.

Если взять регистры РАУЗа, то самый маленький - это аналитика вида учета. Там порядка 20 тыс. записей. Дальше аналитика учета затрат - 80 тыс. записей. Еще дальше - аналитика учета партий. Там около 200 тыс. записей уже. Когда оптимизировался было 150 тыс.

Вся "проблема" в спец. одежде. Если её выкинуть, то да, процедура по чтению ключей вызывается 3 или 4 раза.

Количество вызовов смотрел замером производительности. Не поверил. Поставил итератор. Сходится. Могу скрин в ЛС кинуть, если интересно. Не могу тут прицепить изображение.
43. AlexBar (AlexBar) 09.10.14 11:13
(42) DNSokol,
Я немного потерян. О чем мы сейчас говорим? Об РСВ или хоз.документах? Если о хоз.документах тогда количество вызовов становится вполне понятным если все записи являются уникальными. Если об РСВ, то укажи мне откуда производятся такие многочисленные вызовы. У меня конечно не так много спец***, но если следовать твоим рассуждениям, то в любом случае указанные функции должны вызываться столько раз, сколько различных аналитик имеется в регистре учета затрат. Я продолжаю тему только по одной причине: я не поленился внести указанные тобой изменения. Если до этих изменений РСВ проводился 9:35, то с внесенными изменениями после реиндексации и реструктуризации регистров получил время 9:29. Выигрыш в пределах погрешностей, связанных с нагрузкой на сервер рабочими базами. Однако твои результаты иные: с 2-х часов до 10-ти минут. Другой коллега заявил что ускорение 30-ти кратное. Цифры впечатляющие. Но я пытаюсь докопаться до сути.
Если ты решишь не продолжать дальше тему, то достаточно сказать: Леша, давай тему закроем. :)
44. Дмитрий Соколов (DNSokol) 09.10.14 12:21
(43) AlexBar,

Написал же... Речь о хоз. документах естественно в части создания и РСВ - в части чтения. Документ "Передача материалов в эксплуатацию" создает много уникальных ключей, которые потом вычитываются РСВ.

Если смотреть по этапам:

Этап 1. Первичные документы (конкретно по спец**) в течение месяца формируют множество уникальных ключей.

Этап 2. Документами Корректировка НЗП так же походу создаются ключи (или читаются). документы делают бухгалтера перед закрытием.

Этап 3. Документом "расчет себестоимости" вызывается процедура "ПроцедурыРасчетаСебестоимостиРасширеннаяАналитика.ВыполнитьДействияДокумента", которая в конечном счете приводит к вызову "ВыполнитьРаспределениеЗатрат", которая в свою очередь в цикле вызывает следующую функцию:
					// Заполним аналитику получателя (кор. аналитику)
					АналитикаПолучателя = ПолучитьАналитикуПолучателя(СтрокаБазы, СтрокаДанныеИсточника, ПравилоРаспределения, СтруктураШапкиДокумента);

...Показать Скрыть


Тут АналитикаПолучателя - это тот самый пресловутый "кэш", который на самом деле не кэш, а набор ключей для дальнейшего расчета. Ну и понятно, что при каждом вызове в цикле функции "ПолучитьАналитикуПолучателя" производится сброс этого кэша, т.к.

// Возвращает аналитику получателя согласно способу определения аналитики, который указан в правиле распределения.
//
Функция ПолучитьАналитикуПолучателя(СтрокаБазы, СтрокаИсточника, ПравилоРаспределения, СтруктураШапкиДокумента)
	
	АналитикаПолучателя = Новый Структура;

...Показать Скрыть


Соответственно, если повторное значение не использовать, то при каждом вызове "ПолучитьАналитикуПолучателя" происходит чтение базы. При повторном использовании заполнение структуры "АналитикаПолучателя" производится сильно быстрее, т.к. при одинаковом наборе входящих параметров мы читаем базу только при первом вызове ПолучитьАналитикуПолучателя. При всех последующих вызовах то, что уже закэшировано сервером - просто возвращается. Чтение базы происходит только по тем ключам, которые не были получены ранее.

Надеюсь, теперь понятнее объяснил. Или нет? Что не понятно?
45. Дмитрий Соколов (DNSokol) 09.10.14 12:43
(43) AlexBar,
И да, похожая "петрушка" наблюдается еще на строительстве, где много отношений с комиссионерами. У меня есть такой филиал. АналитикаУчетаПартий содержит 20 тыс. уникальных строчек (уникальные пары Комиссионер/Договор), но, считается по ним всё очень быстро, т.к. нет кучи циклов. По комиссионерам ключ/значение читается только 1 раз, и далеко не все 20 тыс. записей (в отличие от спец**), т.к. отношения эти не долгоиграющие.
46. Антон Стеклов (asved.ru) 11.10.14 20:40
(39) DNSokol,
С выключенной галкой "индексировать" время расчета себестоимости 11:20. Если включаем эту галочку и проводим расчет себестоимости, то время получается 8:02.


А план запроса показать стесняемся?
ojiojiowka; +1 Ответить 1
47. John Smith (PiccaHut001) 15.10.14 13:11
(46) asved.ru, вы *а****и уже, план запроса не показатель, он может быть разным для одной базы, после ночной индексации он один, вечером, после активной работы - другой. Мы же оптимизируем 1С, какой тогда смысл его выкладывать?
48. Николай Терновой (ojiojiowka) 15.10.14 13:27
Наверное потомучто он зависит еще и от существующих индексов и всем интересно чем созданный доп индекс лучше кластерного по измерениям.
49. leo-i (leo-i) 24.01.15 12:39
Добавьте тогда и это:
ШаблонИзмеренийИзМакета(ИмяРегистра).

И пара вопросов:

1. Почему выбрали свойство "Повторное использование возвращаемых значений" - "На время сеанса", а не "На время вызова"?
2. Чем на Ваш взгляд может быть чревато включение в модуль "РасширеннаяАналитикаУчетаПовторноеИспользование" функции СформироватьЗапросПоЗначениямАналитики(СправочникСсылка)?

50. Дмитрий Соколов (DNSokol) 27.01.15 12:13
(49) leo-i,

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

По вопросам:
1. На сколько я понял из описаний, то при установке значения повторного использования "на время вызова", то по окончании работы процедуры на стороне сервера, кэш слетает, а если выбрать "на время сеанса", то кэш существует на все время сеанса работы, т.е. пока клиентское приложение не закроется. Т.к. в расчете себестоимости постоянно вызовы между клиентом и сервером прыгают, то я подумал, что лучше режим выбрать "на время сеанса", хотя, тут может и не сильно прав... нужно будет поиграть с вызовами, посмотреть, к чему это приведет.

2. На первый взгляд - ничем. Но, могу заблуждаться. нужно смотреть откуда функция вызывается.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа