В практике крупных складских комплексов часто возникает задача: необходимо ежедневно рассчитывать стоимость хранения каждой запчасти. Когда номенклатурных позиций становится слишком много (миллионы записей), стандартный подход с ежедневной фиксацией данных в РегистрСведений начинает «тормозить» систему. Мы сталкиваемся с тем, что регламентные задания выполняются часами, а отчеты зависают.
В данной статье мы разберем, почему попытка переложить этот функционал на механизмы, аналогичные расчету зарплаты в ЗУП, может быть неоправданной, и проанализируем наиболее эффективные архитектурные решения для платформы 1С:Предприятие 8.3.
Рассмотрим стандартную ситуацию: разработчик создает периодический РегистрСведений, куда каждую ночь записывается стоимость хранения для каждой детали, находящейся на складе. Если на складе 1 000 000 деталей, то за месяц мы получаем 30 000 000 записей. Это приводит к взрывному росту базы данных и катастрофическому падению производительности при получении срезов данных.
Основная ошибка здесь заключается в избыточности. Если цена хранения детали не менялась в течение месяца, записывать ее 30 раз — нерационально. Нам нужно хранить только изменения состояний.
Часто возникает мысль использовать РегистрРасчета, так как он отлично справляется с начислениями за период. Однако проанализируем ситуацию: регистры расчета в 1С заточены под механизм вытеснения (когда, например, «Больничный» вытесняет «Оклад»). В складской логистике детали обычно не уходят на больничный и не перекрывают периоды хранения друг друга. Использование этого объекта для миллионов позиций может оказаться избыточным и сложным в поддержке, так как механизмы пересчета фактического периода действия на таких объемах будут работать медленно.
Самый эффективный способ — отказаться от ежедневной записи сумм и перейти к расчету «на лету» или по требованию. Мы будем использовать два источника данных:
ТоварыНаСкладах), где записи делаются только в моменты прихода или расхода.РегистраСведений.ЦеныНоменклатуры, где записи делаются только в момент изменения тарифа.Рассмотрим логику запроса. Нам нужно соединить эти таблицы так, чтобы для каждого интервала остатка подобрать актуальную цену на каждый день. Посмотрим на примерную структуру запроса:
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.Количество,
Остатки.Период КАК ДатаНачала,
ДОБАВИТЬКДАТЕ(Остатки.ПериодЗавершения, ДЕНЬ, -1) КАК ДатаОкончания,
Цены.Цена
ИЗ
ВТ_Остатки КАК Остатки
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Цены КАК Цены
ПО Остатки.Номенклатура = Цены.Номенклатура
И Цены.Период МЕЖДУ Остатки.Период И Остатки.ПериодЗавершения
Проанализируем этот подход: мы работаем только с точками изменения. Это в тысячи раз сокращает объем обрабатываемых данных. Для построения итогового отчета за период мы «разворачиваем» эти интервалы по дням только в момент формирования отчета, используя виртуальную таблицу календаря.
Если расчет в реальном времени все же кажется тяжелым, применим метод агрегации. Создадим РегистрНакопления (Обороты), в который будем записывать ресурс КоличествоДнейХранения.
Алгоритм действий следующий:
Номенклатура | Количество | ШтукоДни.ШтукоДни на актуальный тариф.Важный нюанс: этот метод идеально работает, если цена хранения стабильна. Если цена меняется часто, придется делать «срез» накоплений в момент изменения цены.
Вместо того чтобы мучить систему ежедневными регламентными заданиями, перейдем к модели событийного расчета. Рассмотрим создание документа, который будет формироваться раз в месяц или в момент полной отгрузки партии товара (например, по конкретному серийному номеру или ID поставки).
Документ выполняет следующие функции:
Взаиморасчеты или Продажи).Это позволяет избежать хранения миллионов промежуточных записей, которые нужны только для одной цели — выставить счет клиенту или оценить затраты.
Если специфика вашего бизнеса все же требует ежедневной фиксации данных, необходимо оптимизировать сам процесс записи в 1С. Выясним основные причины тормозов: это транзакционные блокировки и запись по одной строке.
Разберем, как правильно организовать запись больших массивов:
Записать() внутри цикла по миллиону позиций. Формируйте наборы записей (по 5 000 – 10 000 строк) и записывайте их порциями.Номенклатура, так как именно по ней чаще всего происходят отборы в запросах.При реализации расчета стоимости хранения важно учитывать логику, принятую в профессиональных системах управления складом (WMS):
Округление периодов: Часто первый и последний дни хранения считаются как полные сутки. В коде 1С это реализуется через функцию НАЧАЛОПЕРИОДА(Дата, ДЕНЬ). Это позволяет избежать ошибок, когда товар пришел вечером, а ушел утром следующего дня.
Дифференцированная шкала: Иногда склад предоставляет «бесплатное окно» (например, первые 3 дня). В этом случае в запросе мы используем условие:
ВЫБОР
КОГДА РАЗНОСТЬДАТ(ДатаПрихода, ДатаТекущая, ДЕНЬ) > БесплатныйПериод
ТОГДА (РАЗНОСТЬДАТ(ДатаПрихода, ДатаТекущая, ДЕНЬ) - БесплатныйПериод) * Цена
ИНАЧЕ 0
КОНЕЦ
Подводя итог, отметим: для решения задачи с миллионами деталей не нужно пытаться «завалить» базу данных записями. Оптимальный путь — это хранение только изменений (состояний) и использование мощного механизма запросов 1С для вычисления итогов в момент обращения к ним. Это сохранит размер базы в разумных пределах и обеспечит высокую скорость работы пользователей.