gifts2017

Ускоряем расчет себестоимости УПП

Опубликовал Антон Ширяев (Антон Ширяев) в раздел Администрирование - Оптимизация БД (HighLoad)

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

Себестоимость у нас считается достаточно долго от 30 минут и больше в зависимости от разных факторов.

Используем партионный учет. Списание партий "по средней" в БУ/НУ, по ФИФО в УУ

Как-то раз решил сделать замер производительности чтобы определить какие операции занимают много времени. Замер приложен в файле ЗамерПроведенияСебестоимости.pff.

Меня очень удивило, что почти 10% общего времени выполнялся код:

    Если Элемент.Ключ = "ВременнаяРазница" или Элемент.Ключ = "ПостояннаяРазница" тогда

Вроде бы ничего криминального, но этот код выполнялся в моем случае в двух местах в общей сложности более 159 млн раз!

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

В приложенном файле КорректировкаСтоимости_РассчитатьСписаниеПоСредней.txt находится уже готовая к применению процедура - просто замените штатную.

Для тех кто не имеет доступ к скачиванию распишу, что исправил в процедуре РассчитатьСписаниеПоСредней() из общего модуля КорректировкаСтоимости УПП 1.3.37.1 (вообще эта процедура не менялась со времен как минимум 1.2.16.1)

Для возможности сравнения времени операции в начало процедуры добавим (учитываем, что ТекущаяУниверсальнаяДатаВМиллисекундах() появилась только в 8.2.17, для более ранних используем просто ТекущаяДата())

    // ША
   
НачалоОперации = ТекущаяУниверсальнаяДатаВМиллисекундах();
   
ИспользоватьМассивы = Истина;
   
// ША

После кода

    СтруктураСостояния = Новый Структура;

Добавим

    // ША
   
Если ИспользоватьМассивы Тогда
       
МассивСостояний = Новый Массив;
       
МассивСостоянийБР = Новый Массив;
    КонецЕсли;
   
// ША

После кода

                СтруктураСостояния.Вставить(Колонка.Имя)

Добавим

                // ША
               
Если ИспользоватьМассивы Тогда
                   
МассивСостояний.Добавить(Колонка.Имя);
                    Если Не
Колонка.Имя = "ВременнаяРазница" И Не Колонка.Имя = "ПостояннаяРазница" Тогда
                       
МассивСостоянийБР.Добавить(Колонка.Имя);
                    КонецЕсли;
                КонецЕсли;
               
// ША

Код

            НайденоСостояние=Истина;
            Для Каждого
Элемент Из СтруктураСостояния Цикл

                Если
Элемент.Ключ = "ВременнаяРазница" или Элемент.Ключ = "ПостояннаяРазница" тогда
                    Продолжить;
                КонецЕсли;
                Если НЕ (
ЭлементСостояние.Значение[Элемент.Ключ] = Строка[Элемент.Ключ]) Тогда

                   
НайденоСостояние = Ложь; // состояния различны

                   
Прервать; // дальше можно не проверять
               
КонецЕсли;
            КонецЦикла;

Заменим на

            НайденоСостояние=Истина;
           
// ША
           
Если ИспользоватьМассивы Тогда
                Для Каждого
Элемент Из МассивСостоянийБР Цикл Если ЭлементСостояние.Значение[Элемент] <> Строка[Элемент] Тогда НайденоСостояние = Ложь; Прервать; КонецЕсли; КонецЦикла;
            Иначе
           
// ША
           
Для Каждого Элемент Из СтруктураСостояния Цикл

                Если
Элемент.Ключ = "ВременнаяРазница" или Элемент.Ключ = "ПостояннаяРазница" тогда
                    Продолжить;
                КонецЕсли;
                Если НЕ (
ЭлементСостояние.Значение[Элемент.Ключ] = Строка[Элемент.Ключ]) Тогда

                   
НайденоСостояние = Ложь; // состояния различны

                   
Прервать; // дальше можно не проверять
               
КонецЕсли;
            КонецЦикла;
            КонецЕсли;
// ША

Код

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

Заменим на

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

Код

            НайденоСостояние=Истина;
            Для Каждого
Элемент Из СтруктураСостояния Цикл

                Если
Элемент.Ключ = "ВременнаяРазница" или Элемент.Ключ = "ПостояннаяРазница" тогда
                    Продолжить;
                КонецЕсли;

                Если НЕ (
ЭлементСостояние.Значение[Элемент.Ключ] = Строка[Элемент.Ключ+ПрефиксПараметровНовогоСостояния]) Тогда

                   
НайденоСостояние = Ложь; // состояния различны

                   
Прервать; // дальше можно не проверять
               
КонецЕсли;
            КонецЦикла;

Заменим на

            НайденоСостояние=Истина;
           
// ША
           
Если ИспользоватьМассивы Тогда
                Для Каждого
Элемент Из МассивСостоянийБР Цикл Если ЭлементСостояние.Значение[Элемент] <> Строка[Элемент + ПрефиксПараметровНовогоСостояния] Тогда НайденоСостояние = Ложь; Прервать; КонецЕсли; КонецЦикла;
            Иначе
            Для Каждого
Элемент Из СтруктураСостояния Цикл

                Если
Элемент.Ключ = "ВременнаяРазница" или Элемент.Ключ = "ПостояннаяРазница" тогда
                    Продолжить;
                КонецЕсли;

                Если НЕ (
ЭлементСостояние.Значение[Элемент.Ключ] = Строка[Элемент.Ключ+ПрефиксПараметровНовогоСостояния]) Тогда

                   
НайденоСостояние = Ложь; // состояния различны

                   
Прервать; // дальше можно не проверять
               
КонецЕсли;
            КонецЦикла;
            КонецЕсли;
// ША

Код

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

Заменим на

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

Для анализа эффекта от кода будем записывать время выполнения процедуры в журнал регистрации. Для этого в конце процедуры добавим

    // ША
   
ЗаписьЖурналаРегистрации("СписаниеПоСредней, сек", УровеньЖурналаРегистрации.Предупреждение, , ,
       
Формат((ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОперации) / 1000, "ЧДЦ=3; ЧГ=0"));
   
// ША

Теперь меняя всего одну строку (ИспользоватьМассивы = Истина/Ложь) в модуле мы можем проверить эффект от предложенных манипуляций. В моем случае время выполнение этой процедуры сократилось примерно в два раза, что уменьшило время расчета себестоимости на величину порядка 7-10 минут. Конечно это не ускорение расчета себестоимости в разы, но неплохое начало оптимизации

Так же значительно ускорилось время проведения документа "Корректировка стоимости списания товаров"

Тестируем, отписываемся о результатах полученных на ваших базах

Отредактировано 13.03.2013
1) Указал что используем партионный учет
2) Добавил пропущенное в тексте статьи заполнение массивов (в прикрепленном файле это было)
3) Добавил, что ускорилось время проведения документа "Корректировка стоимости списания товаров"

Для раскраски кода применялась Разукрашка

Скачать файлы

Наименование Файл Версия Размер
КорректировкаСтоимости_РассчитатьСписаниеПоСредней.txt 56
.txt 18,32Kb
05.03.13
56
.txt 18,32Kb Скачать
ЗамерПроведенияСебестоимости.pff 14
.pff 2,86Mb
05.03.13
14
.pff 2,86Mb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Алекс Ю (AlexO) 05.03.13 16:57
Пример хоть и корявой, но реальной оптимизации УПП :)
И не просто "сферической" УПП, а самого коварного блока - расчет себестоимости.
2. Алекс Ю (AlexO) 05.03.13 17:01
(0) Антон Ширяев,
но этот код выполнялся в моем случае в двух местах в общей сложности более 159 млн раз!

а от чего конкретно зависит столь великое число итераций? Объем регистра, активное использование определенных документов?
3. Kom-off (Kom-off) 05.03.13 17:09
Вот только, автор не указал режим учета затрат: РАУЗ или традиционный учет.
4. Алекс Ю (AlexO) 05.03.13 17:10
(3) Kom-off,
ну этот блок точно не РАУЗ :)
5. Kom-off (Kom-off) 05.03.13 17:15
(4) Да, чудес на свете много.
Поди, знай! (с) Интерны
6. Алекс Ю (AlexO) 05.03.13 17:16
(3) Kom-off,
автор не указал режим учета затрат: РАУЗ

РАУЗ чем и "хорош" (хотя я наоборот - склонен сказать в данном случае "плох"), что не считает "тупо" все, что попало в период, а на основе показателей (которых набирается на порядки меньше, чем реальных исходных данных, "давших" (сформировавших) эти показатели), дает "приближенную" картину по себестоимости каждого товара.
1С считает, что картина "и так сойдет".
Я же считаю - что даже и для сельской местности нужно быть ответственнее и профессиональнее.
Точно "в тютельку" РАУЗ, по-моему, считает только по НДС (отдельным регистром и расчетом) - тут им (1С-у) просто налоговая не дает безобразничать :)
7. Антон Ширяев (Антон Ширяев) 05.03.13 17:21
(2) AlexO,
На самом деле пока не вникал какие именно операции дают столь большие исходные таблицы "ТаблицаТоваров", но очевидно что есть три вложенных цикла которые и дадут столь большой объем итераций.
Плюс ко всему процедура при расчете себестоимости вызывается многократно. Сколько длился каждый вызов покажет журнал регистрации.
8. Антон Ширяев (Антон Ширяев) 05.03.13 17:22
(3) Kom-off,
Используется партионный учет
9. Алекс Ю (AlexO) 05.03.13 17:28
(7) Антон Ширяев,
т.е. зависит здесь просто зависит напрямую от количества товаров в периоде, за который рассчитывается себестоимость?
10. Kom-off (Kom-off) 05.03.13 17:35
(6) Какой-то поток сознания.
11. Алекс Ю (AlexO) 05.03.13 17:45
(10) Kom-off,
предлагаю озвучить "свое" понимание РАУЗ.
Не возбраняется :)
А остальные послушают.
Только без копи-паста 1совых агиток, а как сам вот понял - так и руби.
12. Алекс Ю (AlexO) 05.03.13 17:48
(10) Kom-off,
или напишите сразу - "ниасилил" :)
Ни РАУЗ, ни "потоки сознания".
Только - адаптированные для 1сников агитки 1С.
13. Kom-off (Kom-off) 05.03.13 17:48
(12) Без агиток - расчет системы линейных уравнений. Чего тут понимать то?
14. Kom-off (Kom-off) 05.03.13 17:49
(12)
ли напишите сразу - "ниасилил" :)

Нет. Я так не скажу. "Звиняй", барин.
15. Алекс Ю (AlexO) 05.03.13 18:03
(13) Kom-off,
расчет системы линейных уравнений. Чего тут понимать то?

конечно :)
браво. Достойный ответ 1сника, читавшего агитки :)
А что рассчитывают эти ЛУ? Какие исходные данные подставляются в уравнения?
16. Доржи Хренов (Кадош) 05.03.13 18:09
(15) AlexO, мальчик, читай умные книжки, и РАУЗ посетит тебя.
17. Алекс Ю (AlexO) 05.03.13 18:14
(16) Кадош,
так, еще один юноша пожаловал :)
Вас посетил РАУЗ уже? Прошу, в двух словах - что это такое.
А иначе - в контейнер с остальными, "знающими" РАУЗ от 1С.
18. Алекс Ю (AlexO) 05.03.13 18:18
(16) Кадош,
читай умные книжки

... хоть бы поискал сначала по инету инфо, что книжек по 1С-РАУЗу - нет.. брошюрки и невнятная методичка с Украины Абрашиной..но куда ж там...
короче, контейнер...
19. Kom-off (Kom-off) 05.03.13 18:18
(17) Вот любитель хамить.
Что тут скажешь: тролль - он и в Африке тролль.
Одно чего стоит:
...РАУЗ... двух словах - что это такое...

В двух словах уже сказано было, названо было агиткой и опять по кругу. Молодец!
20. Доржи Хренов (Кадош) 05.03.13 18:29
(18) AlexO, мдя...ты книжки читать пробовал?
21. Юрий Осипов (yuraos) 05.03.13 18:43
жене сказал - что поехал в командировку,
любовнице сказал - что поехал в колхоз на картошку,
а сам на чердак и .....
Оптимизировать, оптимизировать и еще раз оптимизировать!!!
22. Юрий Осипов (yuraos) 05.03.13 18:55

Для возможности сравнения времени операции в начало процедуры добавим (учитываем, что ТекущаяУниверсальнаяДатаВМиллисекундах() появилась только в 8.2.17, для более ранних используем просто ТекущаяДата())

(21)
для тех, кто не осчастливлен платформой 8.2.17:

// Функция, возвращающая время в миллисекундах или секундах.
//
&НаКлиентеНаСервереБезКонтекста
Функция ВремяВМиллисекундах()
    Попытка
        Script = Новый COMОбъект("MSScriptControl.ScriptControl");
        Script.Language = "javascript";
        Script.Timeout   = -1;
        Время = Script.Eval("var d = new Date(); d.getTime()");
    Исключение
        Время = ТекущаяДата();
    КонецПопытки;
    
    Возврат Время;
КонецФункции
...Показать Скрыть

---
этот пример любезно предложил StepByStep
в своей статье
http://infostart.ru/public/165702/
23. Доржи Хренов (Кадош) 05.03.13 19:05
(18) AlexO, для теоретиков. В одной из ЖКК есть подробный разбор РАУЗа с расчетами и формулами.
Фас, ищи.
24. Александр Капустин (kapustinag) 06.03.13 00:56
Если в этом месте потребуется еще ускорить, даже ценой большего использования памяти, то попробуйте заменить эти многократные проверки равенства строк текстовым константам на проверки равенства чисел или логических переменных. Например, если один раз пройти по структуре или по массиву, и заполнить добавочные элементы примерно так:

Если Элемент.Ключ = "ВременнаяРазница" тогда
Элемент.ПризнакВР = Истина;
КонецЕсли;

то потом вместо сравнений Если Элемент.Ключ = "ВременнаяРазница" Тогда
можно использовать Если Элемент.ПризнакВР Тогда

Это может дать большой выигрыш на многомиллионных повторах.
25. Антон Ширяев (Антон Ширяев) 06.03.13 09:13
(24) kapustinag,
Дело в том, что это уже не нужно :)
Для этого и создано два массива, чтоб закешировать в них только нужные элементы и не проверять условие в цикле
26. Алекс Ю (AlexO) 06.03.13 12:27
(23) Кадош,
В одной из ЖКК есть подробный разбор РАУЗа с расчетами и формулами.

а на Марсе яблони цветут.
Сам факт того, что даже не знаешь - "в каком ЖКК", да еще и подробный (!) разбор, говорит сам за себя.
27. Доржи Хренов (Кадош) 06.03.13 12:41
(26) AlexO, иди еще маме пожалуйся, что тебе не сказали в какой именно из книг, что искать.
Наверняка больше азбуки в школе ничего не прочитал, ну может быть еще состав на балончике с освежителем.
28. Алекс Ю (AlexO) 06.03.13 12:58
(27) Кадош,
задвинься в угол контейнера, друг.
Когда хоть что-то будешь знать - приходи.
А пикироваться с тобой на уровне "В одной из ЖКК" и "Наверняка больше азбуки" - у меня нет времени. Наверняка у тебя есть сотня таких же московских деятелей, равных по разуму, которые с удовольствием продолжат тренд про школу и "там где-то что-то должно же быть", с которыми ты более приятно проведешь время.
29. Доржи Хренов (Кадош) 06.03.13 13:10
(28) AlexO, Ты уже показал себя во всей красе постом о том, что расчет себестоимости с помощью РАУЗ происходит с точностью +- километр. Ах тысячи несчастных российскийх предприятий! Прежде чем выдавать такие тезисы, надо было поработать с РАУЗ хотя бы на 1-2 предприятих.
Ах, да. В вашей деревне только ларьки, которым требуются эникейщики вроде тебя, "компьютерные монстры" так сказать.
30. Доржи Хренов (Кадош) 06.03.13 13:20
(28) AlexO,
вот и читайте книжки (хотя они несут минимум информации) (с) AlexO
Понял, что книги не несут для тебя полезной информации.
Извиняй, друх.
31. Алекс Ю (AlexO) 06.03.13 13:20
(29) Кадош,
Прежде чем выдавать такие тезисы, надо было поработать с РАУЗ хотя бы на 1-2 предприятих.

Если на каких-то несчастных предприятиях деятели вроде тебя "внедрили" (включили галочки) РАУЗ - это не значит, что на предприятии теперь полная прозрачность в учете и реальная цифра на выходе расчета себестоимости.
И живут они, бедные, по принципу "что-то считает - ну и ладно".
32. Алекс Ю (AlexO) 06.03.13 13:22
(30) Кадош,
Понял, что книги не несут для тебя полезной информации.

спасибо за цитирование, но 2 листа агиток 1С я не считаю за "книжки".
Уж извиняйте.
А "водонасыщенные" методички, которые вы так громко назвали "ЖКК" никакой инфо, кроме "как включить учет по РАУЗ", не несут.
33. Kom-off (Kom-off) 06.03.13 13:23
(28)
А пикироваться с тобой на уровне "В одной из ЖКК" и "Наверняка больше азбуки" - у меня нет времени.

Судя по количеству постов автора (28) - нас зло обманывают :-)
34. Алекс Ю (AlexO) 06.03.13 13:32
(30) Кадош,
Извиняй, друх.

И не надо меня принимать в ваше московское общество "избранных".
Я не такой :)
Просто "извиняй, друг" достаточно.
(33) Kom-off,
нас зло обманывают :-)

ну вас, может, и обманывают - но, верно, "и сам обманываться рад" (с) :)
А мне еще ни на один вопрос здесь ни вы, ни другие, кроме автора статьи, не ответили по предмету.
(чтобы не возникло новых "подпрыгиваний" вокруг этой фразы - не привели ни одного понимания; если понятно выражаюсь).
35. Доржи Хренов (Кадош) 06.03.13 13:33
(31) AlexO, бгггг...палишься. РАУЗ это не галочки.
36. Доржи Хренов (Кадош) 06.03.13 13:34
(32) AlexO, скажи сразу, что уровень умственного развития не позволяет понимать ЖКК.
37. Kom-off (Kom-off) 06.03.13 13:38
(34)
А мне еще ни на один вопрос здесь ни вы, ни другие, кроме автора статьи, не ответили по предмету.

Да и сами Вы, сударь, ничего путного по этому вопросу не сказали, однако.
Как говорится:
...нечего не зеркало пенять...
(с) Иван Крылов. Зеркало и обезъяна.
38. hasp_x 06.03.13 15:23
Если учесть, что на блоке себестоимости в 1С сидят наиболее крутые перцы, то автору тем-более большой жирный плюс
39. Юрий Осипов (yuraos) 06.03.13 17:56
(38) hasp_x,
простите пожалусто за нескромный вопрос:
а что именно у тех самых перцев СамоеЕ крУТое ???
40. г. Казань Рустем Гумеров (Rustig) 06.03.13 19:05
(0) плюсую за находчивость и сообразительность! :)
...однажды основательно поменял код типовой конфы (в БП 2.0 механизмы учета ОС - практически всю подсистему переписал), увеличил производительность алгоритмов.
Но привычки критически относиться к коду типовых конфигураций в тот раз не сформировалось.
А теперь на уровне подсознания зафиксировался вопрос: а не прогнать ли тест на производительность?
semen_2008; +1 Ответить
41. Антон Ширяев (Антон Ширяев) 13.03.13 11:55
Исправил и немного дополнил статью
1) Указал что используем партионный учет
2) Добавил пропущенное в тексте статьи заполнение массивов (в прикрепленном файле это было)
3) Добавил, что ускорилось время проведения документа "Корректировка стоимости списания товаров"
4) Исправил версию УПП на которой проверял - обновил до 1.3.37.1
42. Алекс Ю (AlexO) 14.03.13 12:58
(41) Антон Ширяев,
4) Исправил версию УПП на которой проверял - обновил до 1.3.37.1

Да там годами ничего не меняется :)
Не то, что в версиях.
43. Михаил Швец (MiCe) 19.03.13 01:43
рауз - идея хорошая.... но как всегда 1с реализация ж..а
и навязывание ее еще большая зад..ца
особенно в ут... просто ....
ихние теоретики хромают что с практикой ... да и теорией ....
44. Наталья Ефимова (Pushast) 10.06.13 10:35
РАУЗ..рауз...
единственная книга ко мне в руки попала в 170 страничек (отечественная), надеюсь ее в сети еще не затерли, а то старался... картинки сляпывал:)
А вот с расчетом себестоимости у меня засада - у всех главбухов жажда - закрыть счет 20 за каждый день. И стандартный механизм расчета себестоимости "доломали" до состояния расчета с/с за каждый день.
Мне жалко усилий парниши-программера... Если расчет с/с вне зависимости -за один день или месяц у меня укладывается в полчаса - это "щастье"! А, в довесок, и если при этом не весят все остальные (операторы на реализации)...а это редкость:(
45. isn Игнатьев (isn) 16.10.13 16:38
за РАУЗ как таковой будущее расчета себестоимости, так что нам, программерам "пилить" да "пилить".
SunShinne; +1 Ответить