Персональная страница Федора Езеева
Главная
Download
Ссылки
MS SQL
Обмен данными
Новости
Статьи
О себе
Крупные разделы...
Коллективная разработка
1С++, OOP, XP
FuncTest
FAQ
Структура 1cv7.md

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

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

Так поступил и я. И обнаружил (и это довольно частая картина), что 95% времени выполняются два запроса. Итоговое время выполнения - около 170 секунд. Вот текст самого толстого запроса (65% времени). Второй запрос был похож на первый и сделанные в нем изменения оказались идентичными.


ТЗ="Период с ДатаНачала По ДатаКон;
|Фирма=Регистр.НДСприобретенныхТоваров.Поставка.Фирма;
|КредДокумент=Регистр.НДСприобретенныхТоваров.Поставка;
|Докум=Регистр.НДСприобретенныхТоваров.ТекущийДокумент;
|НДС=Регистр.НДСприобретенныхТоваров.НДС;
|ОблагаемаяБазаНДС=Регистр.НДСприобретенныхТоваров.ОблагаемаяБазаНДС;
|СтавкаНДС=Регистр.НДСприобретенныхТоваров.СтавкаНДС;
|КодОперации=Регистр.НДСприобретенныхТоваров.КодОперации;
|Условие(Фирма=ВыбФирма);
|Группировка КредДокумент;
|Группировка Докум;
|Условие ((КодОперации=ЗачтенНДСОплаченногоТовара) ИЛИ 
|	(КодОперации=СписанНДСВозвращенногоНеоплаченногоТовара));
|Функция РасхНДС10= Расход(НДС) когда ((глПроцентНДС(СтавкаНДС)>0) и 
|	(глПроцентНДС(СтавкаНДС)<=10));
|Функция РасхНДС20= Расход(НДС) когда (глПроцентНДС(СтавкаНДС)>10);
|Функция БазаБезНДС= Сумма(ОблагаемаяБазаНДС) когда (глПроцентНДС(СтавкаНДС)=0);
|Функция БазаНДС10= Сумма(ОблагаемаяБазаНДС) когда ((глПроцентНДС(СтавкаНДС)>0) и 
|	(глПроцентНДС(СтавкаНДС)<=10));
|Функция БазаНДС20= Сумма(ОблагаемаяБазаНДС) когда (глПроцентНДС(СтавкаНДС)>10);

Первое, на что я обратил внимание - частый вызов функции глПроцентНДС(). Смотрим ее текст.

Функция глПроцентНДС(Ставка) Экспорт
	Если ТипЗначенияСтр(Ставка)="Справочник" Тогда
		Если Ставка.Вид()="СтавкиНДС" Тогда
			Возврат Ставка.Ставка;
		КонецЕсли;
	КонецЕсли;
	Возврат 0;
КонецФункции

Проверки - это, конечно, хорошо, но не для этого случая. Я могу быть уверенным в корректности передаваемых данных. Меняю в запросе вызов глПроцентНДС(СтавкаНДС) на СтавкаНДС.Ставка. Проверяю, время выполнения падает на 30 секунд!

Думаю дальше. Сама СтавкаНДС, как элемент справочника меня не интересует - исключительно значение реквизита Ставка. Меняю объявление переменной, и все места, где ее использую. Получается такой запрос:

|Фирма=Регистр.НДСприобретенныхТоваров.Поставка.Фирма;
|КредДокумент=Регистр.НДСприобретенныхТоваров.Поставка;
|Докум=Регистр.НДСприобретенныхТоваров.ТекущийДокумент;
|НДС=Регистр.НДСприобретенныхТоваров.НДС;
|ОблагаемаяБазаНДС=Регистр.НДСприобретенныхТоваров.ОблагаемаяБазаНДС;
|СтавкаНДС=Регистр.НДСприобретенныхТоваров.СтавкаНДС.Ставка;
|КодОперации=Регистр.НДСприобретенныхТоваров.КодОперации;
|Условие(Фирма=ВыбФирма);
|Группировка КредДокумент;
|Группировка Докум;
|Условие ((КодОперации=ЗачтенНДСОплаченногоТовара) ИЛИ 
|	(КодОперации=СписанНДСВозвращенногоНеоплаченногоТовара));
|Функция РасхНДС10= Расход(НДС) когда ((СтавкаНДС>0) и (СтавкаНДС<=10));
|Функция РасхНДС20= Расход(НДС) когда (СтавкаНДС>10);
|Функция БазаБезНДС= Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС=0);
|Функция БазаНДС10= Сумма(ОблагаемаяБазаНДС) когда ((СтавкаНДС>0) и (СтавкаНДС<=10));
|Функция БазаНДС20= Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС>10);

Ускорение составляет еще около 30-ти секунд! Вместо 168 секунд отчет строится теперь за 108. Иду далее. В типовых частенько в условиях используется не оператор ИЛИ, а проверяется попадание в список значений. Пробую сделать так:

КодыОпераций=СоздатьОбъект("СписокЗначений");
КодыОпераций.ДобавитьЗначение(ЗачтенНДСОплаченногоТовара);
КодыОпераций.ДобавитьЗначение(СписанНДСНеоплаченногоТовара);
, а в запросе Условие теперь выглядит так:
|Условие (КодОперации в КодыОпераций);
Ускорение еще на 10 секунд!

Воодушевленный этим успехом, захотел и ставки НДС раскидать по спискам значений. Делаю таким образом:

СписокСтавок10=СоздатьОбъект("СписокЗначений");
СписокСтавок20=СоздатьОбъект("СписокЗначений");
СписокСтавок0=СоздатьОбъект("СписокЗначений");
	
СтавкиНДС=СоздатьОбъект("Справочник.СтавкиНДС");
СтавкиНДС.ВыбратьЭлементы();
Пока СтавкиНДС.ПолучитьЭлемент()=1 Цикл
	Если СтавкиНДС.Ставка=0 Тогда
		СписокСтавок0.ДобавитьЗначение(СтавкиНДС.ТекущийЭлемент());
	ИначеЕсли СтавкиНДС.Ставка <= 10 Тогда
		СписокСтавок10.ДобавитьЗначение(СтавкиНДС.ТекущийЭлемент());
	Иначе
		СписокСтавок20.ДобавитьЗначение(СтавкиНДС.ТекущийЭлемент());
	КонецЕсли;
КонецЦикла;
в запросе, соответственно, переменная СтавкаНДС опять потеряла атрибут .Ставка на конце, а блок функций выглядит так:
|Функция РасхНДС10= Расход(НДС) когда (СтавкаНДС в СписокСтавок10);
|Функция РасхНДС20= Расход(НДС) когда (СтавкаНДС в СписокСтавок20);
|Функция БазаБезНДС=Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС в СписокСтавок0);
|Функция БазаНДС10= Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС в СписокСтавок10);
|Функция БазаНДС20= Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС в СписокСтавок20);
Еще 10 секунд!

И в заключение, мне не понравилась группировка "Докум". У нас ведь есть предопределенная группировка "Документ". Это правда потребовало легких изменений в модуль обхода по запросу, но после приведения запроса к такому виду:

|Фирма=Регистр.НДСприобретенныхТоваров.Поставка.Фирма;
|КредДокумент=Регистр.НДСприобретенныхТоваров.Поставка;
|НДС=Регистр.НДСприобретенныхТоваров.НДС;
|ОблагаемаяБазаНДС=Регистр.НДСприобретенныхТоваров.ОблагаемаяБазаНДС;
|СтавкаНДС=Регистр.НДСприобретенныхТоваров.СтавкаНДС;
|КодОперации=Регистр.НДСприобретенныхТоваров.КодОперации;
|Группировка КредДокумент;
|Группировка Документ;
|Условие (Фирма=ВыбФирма);
|Условие (КодОперации в СписокКодовОперации);
|Функция РасхНДС10= Расход(НДС) когда (СтавкаНДС в СписокСтавок10);
|Функция РасхНДС20= Расход(НДС) когда (СтавкаНДС в СписокСтавок20);
|Функция БазаБезНДС=Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС в СписокСтавок0);
|Функция БазаНДС10= Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС в СписокСтавок10);
|Функция БазаНДС20= Сумма(ОблагаемаяБазаНДС) когда (СтавкаНДС в СписокСтавок20);
Время выполнения уменьшилось еще на 5 секунд и составило 83 секунды. То есть, суммарно, отчет ускорился вдвое.

Rambler's Top100 1C:TOP-100

© 1998-2004 Fedor Ezeev.

Last updated: 2005-09-05