Технология кэширования результата разузлования продукции по спецификации

10.06.19

Разработка - Механизмы типовых конфигураций

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

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Технология кэширования результата разузлования продукции по спецификации:
.cf 15,36Kb
6
6 Скачать (1 SM) Купить за 1 850 руб.

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

И в голову пришла мысль - почему бы не использовать кэширование полученной на выходе таблицы материалов, чтобы при последующих разузлованиях продукции использовать ее, а не производить заново весь расчет. Скорость разузлования предсказуемо вырастет на порядок и больше (в зависимости от сложности спецификаций)!
Но все оказалось очень непросто..

Очевидно, что для хранения и использования результата разузлования нужен регистр сведений.

В качестве измерений будут объект разузлования (Номенклатура, Характеристика) и спецификация.

Ресурс - таблица материалов, в которой будут храниться рассчитанные по спецификации материалы.

Однако выяснилось, что результат разузлования при расчете зависит еще и от параметров, таких как КоличествоУровнейРазузлования, ПараметрыВыпуска и т.д.

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

Регистр сведений КЭШ_Разузлование

Измерения:
- Номенклатура
- ХарактеристикаНоменклатуры
- Спецификация
- ХэшПараметров (
тип Строка, 100)

Ресурсы:
- ТаблицаМатериалов (
тип ХранилищеЗначения)



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

Перейдем к коду. Непосредственно разузлование продукции производится в УПП (1.2, 1.3) в общем модуле "РазузлованиеНоменклатуры" в функции "РазузловатьНоменклатуру"


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

Функция РазузловатьНоменклатуру(Источник, Результат = Неопределено, Параметры = Неопределено) Экспорт

    Если Константы.ИспользоватьКэш.Получить() Тогда
       
        КопияПараметры = Новый Структура();
        Для Каждого Параметр Из Параметры Цикл

            // Исключаем параметры, не влияющие на результат разузлования
            Если Параметр.Ключ = "ДатаСпецификации" Тогда
                Продолжить;
            КонецЕсли;
            КопияПараметры.Вставить(Параметр.Ключ, Параметр.Значение);
        КонецЦикла;
        стрXML = СериализоватьОбъектXDTO(КопияПараметры);
        ХэшПараметров= ХэшПараметров(стрXML);


   КонецЕсли;


....      

Функции СериализоватьОбъектXDTO и ХэшПараметров содержатся в конфигурации, прилагаемой к статье.

В процессе разработки выяснилось, что таблицу материалов (результат разузлования) необходимо формировать из расчета на 1 шт объекта разузлования (чтобы в дальнейшем при разузловании например 30 штук продукции, просто умножить каждое количество материала из исходной таблицы на 30).
Для этого было принято решение,  если в данную функцию РазузловатьНоменклатуру передано количество продукции для разузлования не равное 1 (это определяется по параметру передаваемому в функцию Источник.Количество), выполнить вначале разузлование на 1 единицу и сохранить результат разузлования в наш регистр. Причем повторное разузлование не будет выполняться далее, т.к. эту же таблицу мы уже и сможем использовать (будет понятно ниже).

Т.е. добавляем к нашему коду следующее:
   

Если Источник.Количество <> 1 Тогда
            
            УжеРазузловано = Ложь;
            НаборЗаписей = РегистрыСведений.Кэш_Разузлование.СоздатьНаборЗаписей();
            НаборЗаписей.Отбор.Номенклатура.Установить(Источник.Номенклатура);
            НаборЗаписей.Отбор.ХарактеристикаНоменклатуры.Установить(Источник.ХарактеристикаНоменклатуры);
            НаборЗаписей.Отбор.Спецификация.Установить(Источник.Спецификация);
            НаборЗаписей.Отбор.ХэшПараметров.Установить(ХэшПараметров);
            НаборЗаписей.Прочитать();
            УжеРазузловано = (НаборЗаписей.Количество() <> 0);

              Если Не УжеРазузловано Тогда

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

                    // Вот здесь укажем что надо разузловать на 1 единицу объекта разузлования
                    КопияИсточник.Количество = 1;
                    // Выполним разузлование на 1 единицу (причем результат разузлования на 1 единицу
                    // будет записан в наш регистр в конце данной функции (это будет описано чуть ниже)
                    Рез = РазузловатьНоменклатуру(КопияИсточник, Результат, КопияПараметры);
            КонецЕсли;
          


И ниже собственно производим считывание из нашего регистра таблицы материалов (из расчета на 1 шт) для данного объекта разузлования по данной спецификации для данного набора параметров. Если таблица есть, выполним пересчет количества материалов в ней на переданное количество и возвратим таблицу материалов как результат разузлования.
    

  // Типовой код функции
        ИнициализацияПараметров(Параметры);
        ИнициализацияРезультатаРазузлования(Результат, Источник);
        
        МассивОшибок = Новый Массив;
        Уровень = 0;
        // Типовой код функции

        НаборЗаписей = РегистрыСведений.Кэш_Разузлование.СоздатьНаборЗаписей();

        НаборЗаписей.Отбор.Номенклатура.Установить(Источник.Номенклатура);
        НаборЗаписей.Отбор.ХарактеристикаНоменклатуры.Установить(Источник.ХарактеристикаНоменклатуры);
        НаборЗаписей.Отбор.Спецификация.Установить(Источник.Спецификация);
        НаборЗаписей.Отбор.ХэшПараметров.Установить(ХэшПараметров);
        НаборЗаписей.Прочитать();
        

        // Если есть таблица материалов ее и вернем
        Если НаборЗаписей.Количество() <> 0 Тогда
                ЗаписьРегистра = НаборЗаписей[0];
                ТаблицаРазузлования = ЗаписьРегистра.ТаблицаМатериалов.Получить();
                // Пересчитаем количество материалов
                Если Источник.Количество <> 1 Тогда
                    Для Каждого СтрМатериал Из ТаблицаРазузлования Цикл
                        СтрМатериал.Количество = СтрМатериал.Количество * Источник.Количество;
                    КонецЦикла;
                КонецЕсли;
                Результат.ИсходныеКомплектующие = ТаблицаРазузлования ;
                Возврат МассивОшибок;
         КонецЕсли;

Вот и все, осталось только в самом конце функции РазузловатьНоменклатуру (куда при данном алгоритме мы попадем только если разузлование еще не было выполнено) добавить код, записывающий в наш регистр сформированную таблицу материалов (на 1 шт).

........
 

     Если Константы.ИспользоватьКэш.Получить() И Источник.Количество = 1 И МассивОшибок.Количество() = 0 Тогда

             Менеджер = РегистрыСведений.Кэш_Разузлование.СоздатьМенеджерЗаписи();
             ЗаполнитьЗначенияСвойств(Менеджер, Источник);
             Менеджер.ТаблицаМатериалов = Новый ХранилищеЗначения(Результат.ИсходныеКомплектующие, Новый СжатиеДанных(9));
             Менеджер.ХэшПараметров = ХэшПараметров ;
             Менеджер.Записать();

        КонецЕсли;
    
        Возврат МассивОшибок;
    
КонецФункции


В результат функция РазузловатьНоменклатуру выглядит так:


Функция РазузловатьНоменклатуру(Источник, Результат = Неопределено, Параметры = Неопределено) Экспорт
    
    Если Константы.ИспользоватьКэш.Получить() Тогда
        
        КопияПараметры = Новый Структура();
        Для Каждого Параметр Из Параметры Цикл
            Если Параметр.Ключ = "ДатаСпецификации" Тогда
                Продолжить;
            КонецЕсли;
            КопияПараметры.Вставить(Параметр.Ключ, Параметр.Значение);
        КонецЦикла;
        
        стрXML = СериализоватьОбъектXDTO(КопияПараметры);
        ХэшПараметров = ХЭШ(стрXML);
        
        // разузлуем на 1 шт, чтобы потом взять из кэша
        Если Источник.Количество <> 1 Тогда
            
            УжеРазузловано = Ложь;
            НаборЗаписей = РегистрыСведений.Кэш_Разузлование.СоздатьНаборЗаписей();
            НаборЗаписей.Отбор.Номенклатура.Установить(Источник.Номенклатура);
            НаборЗаписей.Отбор.ХарактеристикаНоменклатуры.Установить(Источник.ХарактеристикаНоменклатуры);
            НаборЗаписей.Отбор.Спецификация.Установить(Источник.Спецификация);
            НаборЗаписей.Отбор.ХэшПараметров.Установить(ХэшПараметров);
            НаборЗаписей.Прочитать();
            УжеРазузловано = (НаборЗаписей.Количество() <> 0);
            
            Если Не УжеРазузловано Тогда
                
                // Создадим копии структур Источник и Параметры для расчета на 1 единицу
                КопияИсточник= Новый Структура;
                Для Каждого ЭлементСтруктуры Из Источник Цикл
                    КопияИсточник.Вставить(ЭлементСтруктуры.Ключ, ЭлементСтруктуры.Значение);
                КонецЦикла;
                КопияПараметры = Новый Структура;
                Для Каждого ЭлементСтруктуры Из Параметры Цикл
                    КопияПараметры.Вставить(ЭлементСтруктуры.Ключ, ЭлементСтруктуры.Значение);
                КонецЦикла;
                
                // Вот здесь укажем что надо разузловать на 1 единицу объекта разузлования
                КопияИсточник.Количество = 1;
                // Выполним разузлование на 1 единицу (причем результат разузлования на 1 единицу
                // будет записан в наш регистр в конце данной функции (это будет описано чуть ниже)
                Рез = РазузловатьНоменклатуру(КопияИсточник, Результат, КопияПараметры);
            КонецЕсли;
        КонецЕсли;
        
        // Типовой код УПП
        ИнициализацияПараметров(Параметры);
        ИнициализацияРезультатаРазузлования(Результат, Источник);
        
        МассивОшибок = Новый Массив;
        Уровень = 0;
        // Типовой код УПП
        
        
        НаборЗаписей = РегистрыСведений.Кэш_Разузлование.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Номенклатура.Установить(Источник.Номенклатура);
        НаборЗаписей.Отбор.ХарактеристикаНоменклатуры.Установить(Источник.ХарактеристикаНоменклатуры);
        НаборЗаписей.Отбор.Спецификация.Установить(Источник.Спецификация);
        НаборЗаписей.Отбор.ХэшПараметров.Установить(ХэшПараметров);
        НаборЗаписей.Прочитать();
        
        // Если есть таблица материалов ее и вернем
        Если НаборЗаписей.Количество() <> 0 Тогда
            ЗаписьРегистра = НаборЗаписей[0];
            ТаблицаРазузлования = ЗаписьРегистра.ТаблицаМатериалов.Получить();
            // Пересчитаем количество материалов
            Если Источник.Количество <> 1 Тогда
                Для Каждого СтрМатериал Из ТаблицаРазузлования Цикл
                    СтрМатериал.Количество = СтрМатериал.Количество * Источник.Количество;
                КонецЦикла;
            КонецЕсли;
            Результат.ИсходныеКомплектующие = ТаблицаРазузлования ;
            Возврат МассивОшибок;
        КонецЕсли;        
        
    КонецЕсли;
    
    ИнициализацияПараметров(Параметры);
    ИнициализацияРезультатаРазузлования(Результат, Источник);
    
    МассивОшибок = Новый Массив;
    Уровень = 0;

    
    // типовой код УПП..
    // типовой код УПП..
    // типовой код УПП..
  
    
    // Запишем результат разузлования в регистр
    Если Константы.ИспользоватьКэш.Получить() И Источник.Количество = 1 И МассивОшибок.Количество() = 0 Тогда
        Менеджер = РегистрыСведений.Кэш_Разузлование.СоздатьМенеджерЗаписи();
        ЗаполнитьЗначенияСвойств(Менеджер, Источник);
        Менеджер.ТаблицаМатериалов = Новый ХранилищеЗначения(Результат.ИсходныеКомплектующие, Новый СжатиеДанных(9));
        Менеджер.ХэшПараметров = ХэшПараметров ;
        Менеджер.Записать();
    КонецЕсли;
    
    Возврат МассивОшибок;    
    
КонецФункции // ВыполнитьРазузлование()


Но это еще не все...
Результат разузлования может измениться в результате внесения изменений в спецификацию, в узел спецификации либо в свойство характеристики, которое используется в формулах расчета.

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

Т.е. при изменении спецификации - очищаем все записи регистра по данной спецификации (выполняем в модуле справочника СпецификацииНоменклатуры).
При изменении узла спецификации - очищаем все записи регистра по данному узлу и по спецификации, в которой используется этот узел (выполняем в модуле справочника СпецификацииНоменклатуры).
При изменении свойства характеристики - очищаем все записи регистра по данной характеристике (выполняем в модуле набора записей регистра сведений ЗначенияСвойствОбъектов).

Это пожалуй самый "узкий" момент, т.к. ошибка здесь чревата получением некорректных данных из регистра. Но результат того стоит, поверьте))

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

На этом все. Согласен, что вариант решения небезупречный, скорее всего потребует доработки. Но надеюсь, что он окажется полезен кому-то.
Открыт для критики и предложений по усовершенствованию! Спасибо)

УПП разузлование продукции спецификация кэширование производство производственный учет

См. также

Механизмы типовых конфигураций Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

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

27.02.2025    627    PROSTO-1C    0    

5

Механизмы типовых конфигураций HighLoad оптимизация Программист Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бухгалтерский учет Бесплатно (free)

Пример популярной пользовательской настройки плана счетов. К чему это может привести, почему «всё тормозит» и как это поправить.

18.02.2025    3086    pbelousov    10    

6

Механизмы типовых конфигураций Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Расчет себестоимости в типовых конфигурациях 1С – для многих «черный ящик», работающий по жестко зашитым в него алгоритмам. Реализация этого «черного ящика» может меняться в зависимости от конкретной конфигурации – УПП, БП 3.0, ERP. Но принцип работы везде одинаковый. Расскажем о том, как устроен расчет себестоимости, как его дорабатывать, и какие методы могут быть эффективны и без доработок.

27.12.2024    13243    Begemoth80    32    

86

СКД Механизмы типовых конфигураций Запросы Программист Платформа 1С v8.3 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Россия Бесплатно (free)

Работая с типовыми отчетами в конфигурациях «Зарплата и управление персоналом, редакция 3», «Зарплата и кадры государственного учреждения, редакция 3» и подобных, в схемах компоновки данных можно встретить конструкции запросов, которые обращаются к некоторым виртуальным таблицам.

20.08.2024    2946    PROSTO-1C    0    

22
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Mkonst 58 01.03.19 08:26 Сейчас в теме
Не проще разузлование делать в несколько потоков, (ФоновыеЗадания использовать) ?
2. NoRazum 30 03.11.22 06:55 Сейчас в теме
Такое для ЕРП делал.
В УПП не стал реализовывать.
3. user1959620 15.06.23 13:59 Сейчас в теме
Как то сложно, мне удобнее так:

&НаКлиенте
Процедура ОткрытьСпецификацию(Команда)
ТСТЧ =Элементы.Список.ТекущиеДанные;
Если ТСТЧ<>Неопределено Тогда
Док = ВернутьСпецификацию(ТСТЧ.Ссылка);
ПараметрыФормы = Новый Структура("Ключ", Док);
ПараметрыФормы.Вставить("Изделие", ТСТЧ.Ссылка);
ОткрытьФорму("Документ.Спецификация.ФормаОбъекта", ПараметрыФормы, ЭтаФорма, УникальныйИдентификатор);
Иначе
Сообщить("Нужно установить курс на издетелие, по которому необходимо открыть спецификацию");
КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ВернутьСпецификацию(Изделие)
Возврат Документы.Спецификация.НайтиПоРеквизиту("Изделие", Изделие);
КонецФункции // ()

и в документе спецификация:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Не ЗначениеЗаполнено(Объект.Изделие) и Параметры.Свойство("Изделие") Тогда
Объект.Изделие = Параметры.Изделие;
КонецЕсли;
КонецПроцедуры
Оставьте свое сообщение