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

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

Себестоимость у нас считается достаточно долго от 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) Добавил, что ускорилось время проведения документа «Корректировка стоимости списания товаров»

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

45 Comments

  1. AlexO

    Пример хоть и корявой, но реальной оптимизации УПП 🙂

    И не просто «сферической» УПП, а самого коварного блока — расчет себестоимости.

    Reply
  2. AlexO

    (0) Антон Ширяев,

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

    а от чего конкретно зависит столь великое число итераций? Объем регистра, активное использование определенных документов?

    Reply
  3. Kom-off

    Вот только, автор не указал режим учета затрат: РАУЗ или традиционный учет.

    Reply
  4. AlexO

    (3) Kom-off,

    ну этот блок точно не РАУЗ 🙂

    Reply
  5. Kom-off

    (4) Да, чудес на свете много.

    Поди, знай! (с) Интерны

    Reply
  6. AlexO

    (3) Kom-off,

    автор не указал режим учета затрат: РАУЗ

    РАУЗ чем и «хорош» (хотя я наоборот — склонен сказать в данном случае «плох»), что не считает «тупо» все, что попало в период, а на основе показателей (которых набирается на порядки меньше, чем реальных исходных данных, «давших» (сформировавших) эти показатели), дает «приближенную» картину по себестоимости каждого товара.

    1С считает, что картина «и так сойдет».

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

    Точно «в тютельку» РАУЗ, по-моему, считает только по НДС (отдельным регистром и расчетом) — тут им (1С-у) просто налоговая не дает безобразничать 🙂

    Reply
  7. Антон Ширяев

    (2)

    На самом деле пока не вникал какие именно операции дают столь большие исходные таблицы «ТаблицаТоваров», но очевидно что есть три вложенных цикла которые и дадут столь большой объем итераций.

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

    Reply
  8. Антон Ширяев

    (3) Kom-off,

    Используется партионный учет

    Reply
  9. AlexO

    (7) Антон Ширяев,

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

    Reply
  10. Kom-off

    (6) Какой-то поток сознания.

    Reply
  11. AlexO

    (10) Kom-off,

    предлагаю озвучить «свое» понимание РАУЗ.

    Не возбраняется 🙂

    А остальные послушают.

    Только без копи-паста 1совых агиток, а как сам вот понял — так и руби.

    Reply
  12. AlexO

    (10) Kom-off,

    или напишите сразу — «ниасилил» 🙂

    Ни РАУЗ, ни «потоки сознания».

    Только — адаптированные для 1сников агитки 1С.

    Reply
  13. Kom-off

    (12) Без агиток — расчет системы линейных уравнений. Чего тут понимать то?

    Reply
  14. Kom-off

    (12)

    ли напишите сразу — «ниасилил» 🙂

    Нет. Я так не скажу. «Звиняй», барин.

    Reply
  15. AlexO

    (13) Kom-off,

    расчет системы линейных уравнений. Чего тут понимать то?

    конечно 🙂

    браво. Достойный ответ 1сника, читавшего агитки 🙂

    А что рассчитывают эти ЛУ? Какие исходные данные подставляются в уравнения?

    Reply
  16. Кадош

    (15) мальчик, читай умные книжки, и РАУЗ посетит тебя.

    Reply
  17. AlexO

    (16) Кадош,

    так, еще один юноша пожаловал 🙂

    Вас посетил РАУЗ уже? Прошу, в двух словах — что это такое.

    А иначе — в контейнер с остальными, «знающими» РАУЗ от 1С.

    Reply
  18. Kom-off

    (17) Вот любитель хамить.

    Что тут скажешь: тролль — он и в Африке тролль.

    Одно чего стоит:

    …РАУЗ… двух словах — что это такое…

    В двух словах уже сказано было, названо было агиткой и опять по кругу. Молодец!

    Reply
  19. AlexO

    (16) Кадош,

    читай умные книжки

    … хоть бы поискал сначала по инету инфо, что книжек по 1С-РАУЗу — нет.. брошюрки и невнятная методичка с Украины Абрашиной..но куда ж там…

    короче, контейнер…

    Reply
  20. Кадош

    (18) мдя…ты книжки читать пробовал?

    Reply
  21. yuraos

    жене сказал — что поехал в командировку,

    любовнице сказал — что поехал в колхоз на картошку,

    а сам на чердак и …..

    Оптимизировать, оптимизировать и еще раз оптимизировать!!!

    Reply
  22. yuraos

    Для возможности сравнения времени операции в начало процедуры добавим (учитываем, что ТекущаяУниверсальнаяДатаВМиллисекундах() появилась только в 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/

    Reply
  23. Кадош

    (18) для теоретиков. В одной из ЖКК есть подробный разбор РАУЗа с расчетами и формулами.

    Фас, ищи.

    Reply
  24. kapustinag

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

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

    Элемент.ПризнакВР = Истина;

    КонецЕсли;

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

    можно использовать Если Элемент.ПризнакВР Тогда

    Это может дать большой выигрыш на многомиллионных повторах.

    Reply
  25. Антон Ширяев

    (24) kapustinag,

    Дело в том, что это уже не нужно 🙂

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

    Reply
  26. AlexO

    (23) Кадош,

    В одной из ЖКК есть подробный разбор РАУЗа с расчетами и формулами.

    а на Марсе яблони цветут.

    Сам факт того, что даже не знаешь — «в каком ЖКК», да еще и подробный (!) разбор, говорит сам за себя.

    Reply
  27. AlexO

    (27) Кадош,

    задвинься в угол контейнера, друг.

    Когда хоть что-то будешь знать — приходи.

    А пикироваться с тобой на уровне «В одной из ЖКК» и «Наверняка больше азбуки» — у меня нет времени. Наверняка у тебя есть сотня таких же московских деятелей, равных по разуму, которые с удовольствием продолжат тренд про школу и «там где-то что-то должно же быть», с которыми ты более приятно проведешь время.

    Reply
  28. Кадош

    (28) Ты уже показал себя во всей красе постом о том, что расчет себестоимости с помощью РАУЗ происходит с точностью +- километр. Ах тысячи несчастных российскийх предприятий! Прежде чем выдавать такие тезисы, надо было поработать с РАУЗ хотя бы на 1-2 предприятих.

    Ах, да. В вашей деревне только ларьки, которым требуются эникейщики вроде тебя, «компьютерные монстры» так сказать.

    Reply
  29. AlexO

    (29) Кадош,

    Прежде чем выдавать такие тезисы, надо было поработать с РАУЗ хотя бы на 1-2 предприятих.

    Если на каких-то несчастных предприятиях деятели вроде тебя «внедрили» (включили галочки) РАУЗ — это не значит, что на предприятии теперь полная прозрачность в учете и реальная цифра на выходе расчета себестоимости.

    И живут они, бедные, по принципу «что-то считает — ну и ладно».

    Reply
  30. Кадош

    (28)

    вот и читайте книжки (хотя они несут минимум информации) (с) AlexO

    Понял, что книги не несут для тебя полезной информации.

    Извиняй, друх.

    Reply
  31. AlexO

    (30) Кадош,

    Понял, что книги не несут для тебя полезной информации.

    спасибо за цитирование, но 2 листа агиток 1С я не считаю за «книжки».

    Уж извиняйте.

    А «водонасыщенные» методички, которые вы так громко назвали «ЖКК» никакой инфо, кроме «как включить учет по РАУЗ», не несут.

    Reply
  32. Kom-off

    (28)

    А пикироваться с тобой на уровне «В одной из ЖКК» и «Наверняка больше азбуки» — у меня нет времени.

    Судя по количеству постов автора (28) — нас зло обманывают 🙂

    Reply
  33. AlexO

    (30) Кадош,

    Извиняй, друх.

    И не надо меня принимать в ваше московское общество «избранных».

    Я не такой 🙂

    Просто «извиняй, друг» достаточно.

    (33) Kom-off,

    нас зло обманывают 🙂

    ну вас, может, и обманывают — но, верно, «и сам обманываться рад» (с) 🙂

    А мне еще ни на один вопрос здесь ни вы, ни другие, кроме автора статьи, не ответили по предмету.

    (чтобы не возникло новых «подпрыгиваний» вокруг этой фразы — не привели ни одного понимания; если понятно выражаюсь).

    Reply
  34. Кадош

    (31) бгггг…палишься. РАУЗ это не галочки.

    Reply
  35. Кадош

    (32) скажи сразу, что уровень умственного развития не позволяет понимать ЖКК.

    Reply
  36. Kom-off

    (34)

    А мне еще ни на один вопрос здесь ни вы, ни другие, кроме автора статьи, не ответили по предмету.

    Да и сами Вы, сударь, ничего путного по этому вопросу не сказали, однако.

    Как говорится:

    …нечего не зеркало пенять…

    (с) Иван Крылов. Зеркало и обезъяна.
    Reply
  37. hasp_x

    Если учесть, что на блоке себестоимости в 1С сидят наиболее крутые перцы, то автору тем-более большой жирный плюс

    Reply
  38. yuraos

    (38) hasp_x,

    простите пожалусто за нескромный вопрос:

    а что именно у тех самых перцев СамоеЕ крУТое ???

    Reply
  39. Rustig

    (0) плюсую за находчивость и сообразительность! 🙂

    …однажды основательно поменял код типовой конфы (в БП 2.0 механизмы учета ОС — практически всю подсистему переписал), увеличил производительность алгоритмов.

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

    А теперь на уровне подсознания зафиксировался вопрос: а не прогнать ли тест на производительность?

    Reply
  40. Антон Ширяев

    Исправил и немного дополнил статью

    1) Указал что используем партионный учет

    2) Добавил пропущенное в тексте статьи заполнение массивов (в прикрепленном файле это было)

    3) Добавил, что ускорилось время проведения документа «Корректировка стоимости списания товаров»

    4) Исправил версию УПП на которой проверял — обновил до 1.3.37.1

    Reply
  41. AlexO

    (41) Антон Ширяев,

    4) Исправил версию УПП на которой проверял — обновил до 1.3.37.1

    Да там годами ничего не меняется 🙂

    Не то, что в версиях.

    Reply
  42. MiCe

    рауз — идея хорошая…. но как всегда 1с реализация ж..а

    и навязывание ее еще большая зад..ца

    особенно в ут… просто ….

    ихние теоретики хромают что с практикой … да и теорией ….

    Reply
  43. Pushast

    РАУЗ..рауз…

    единственная книга ко мне в руки попала в 170 страничек (отечественная), надеюсь ее в сети еще не затерли, а то старался… картинки сляпывал:)

    А вот с расчетом себестоимости у меня засада — у всех главбухов жажда — закрыть счет 20 за каждый день. И стандартный механизм расчета себестоимости «доломали» до состояния расчета с/с за каждый день.

    Мне жалко усилий парниши-программера… Если расчет с/с вне зависимости -за один день или месяц у меня укладывается в полчаса — это «щастье»! А, в довесок, и если при этом не весят все остальные (операторы на реализации)…а это редкость:(

    Reply
  44. isn

    за РАУЗ как таковой будущее расчета себестоимости, так что нам, программерам «пилить» да «пилить».

    Reply
  45. drugoi_mir
    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *